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 <openthread/commissioner.h>
41 #include <openthread/instance.h>
42 #include <openthread/joiner.h>
43 
44 #include "coap/coap.hpp"
45 #include "common/as_core_type.hpp"
46 #include "common/clearable.hpp"
47 #include "common/equatable.hpp"
48 #include "common/log.hpp"
49 #include "common/message.hpp"
50 #include "common/numeric_limits.hpp"
51 #include "common/string.hpp"
52 #include "mac/mac_types.hpp"
53 #include "meshcop/meshcop_tlvs.hpp"
54 
55 namespace ot {
56 
57 class ThreadNetif;
58 
59 namespace MeshCoP {
60 
61 /**
62  * Represents a Joiner PSKd.
63  *
64  */
65 class JoinerPskd : public otJoinerPskd, public Clearable<JoinerPskd>, public Unequatable<JoinerPskd>
66 {
67 public:
68     static constexpr uint8_t kMinLength = 6;                         ///< Min PSKd string length (excludes null char)
69     static constexpr uint8_t kMaxLength = OT_JOINER_MAX_PSKD_LENGTH; ///< Max PSKd string length (excludes null char)
70 
71     /**
72      * Indicates whether the PSKd if well-formed and valid.
73      *
74      * Per Thread specification, a Joining Device Credential is encoded as uppercase alphanumeric characters
75      * (base32-thread: 0-9, A-Z excluding I, O, Q, and Z for readability) with a minimum length of 6 such characters
76      * and a maximum length of 32 such characters.
77      *
78      * @returns TRUE if the PSKd is valid, FALSE otherwise.
79      *
80      */
IsValid(void) const81     bool IsValid(void) const { return IsPskdValid(m8); }
82 
83     /**
84      * Sets the joiner PSKd from a given C string.
85      *
86      * @param[in] aPskdString   A pointer to the PSKd C string array.
87      *
88      * @retval kErrorNone          The PSKd was updated successfully.
89      * @retval kErrorInvalidArgs   The given PSKd C string is not valid.
90      *
91      */
92     Error SetFrom(const char *aPskdString);
93 
94     /**
95      * Gets the PSKd as a null terminated C string.
96      *
97      * Must be used after the PSKd is validated, otherwise its behavior is undefined.
98      *
99      * @returns The PSKd as a C string.
100      *
101      */
GetAsCString(void) const102     const char *GetAsCString(void) const { return m8; }
103 
104     /**
105      * Gets the PSKd string length.
106      *
107      * Must be used after the PSKd is validated, otherwise its behavior is undefined.
108      *
109      * @returns The PSKd string length.
110      *
111      */
GetLength(void) const112     uint8_t GetLength(void) const { return static_cast<uint8_t>(StringLength(m8, kMaxLength + 1)); }
113 
114     /**
115      * Overloads operator `==` to evaluate whether or not two PSKds are equal.
116      *
117      * @param[in]  aOther  The other PSKd to compare with.
118      *
119      * @retval TRUE   If the two are equal.
120      * @retval FALSE  If the two are not equal.
121      *
122      */
123     bool operator==(const JoinerPskd &aOther) const;
124 
125     /**
126      * Indicates whether a given PSKd string if well-formed and valid.
127      *
128      * @param[in] aPskdString  A pointer to a PSKd string array.
129      *
130      * @sa IsValid()
131      *
132      * @returns TRUE if @p aPskdString is valid, FALSE otherwise.
133      *
134      */
135     static bool IsPskdValid(const char *aPskdString);
136 };
137 
138 /**
139  * Represents a Joiner Discerner.
140  *
141  */
142 class JoinerDiscerner : public otJoinerDiscerner, public Unequatable<JoinerDiscerner>
143 {
144     friend class SteeringData;
145 
146 public:
147     static constexpr uint8_t kMaxLength = OT_JOINER_MAX_DISCERNER_LENGTH; ///< Max length of a Discerner in bits.
148 
149     static constexpr uint16_t kInfoStringSize = 45; ///< Size of `InfoString` to use with `ToString()
150 
151     /**
152      * Defines the fixed-length `String` object returned from `ToString()`.
153      *
154      */
155     typedef String<kInfoStringSize> InfoString;
156 
157     /**
158      * Clears the Joiner Discerner.
159      *
160      */
Clear(void)161     void Clear(void) { mLength = 0; }
162 
163     /**
164      * Indicates whether the Joiner Discerner is empty (no value set).
165      *
166      * @returns TRUE if empty, FALSE otherwise.
167      *
168      */
IsEmpty(void) const169     bool IsEmpty(void) const { return mLength == 0; }
170 
171     /**
172      * Gets the Joiner Discerner's value.
173      *
174      * @returns The Joiner Discerner value.
175      *
176      */
GetValue(void) const177     uint64_t GetValue(void) const { return mValue; }
178 
179     /**
180      * Gets the Joiner Discerner's length (in bits).
181      *
182      * @return The Joiner Discerner length.
183      *
184      */
GetLength(void) const185     uint8_t GetLength(void) const { return mLength; }
186 
187     /**
188      * Indicates whether the Joiner Discerner is valid (i.e. it not empty and its length is within
189      * valid range).
190      *
191      * @returns TRUE if Joiner Discerner is valid, FALSE otherwise.
192      *
193      */
IsValid(void) const194     bool IsValid(void) const { return (0 < mLength) && (mLength <= kMaxLength); }
195 
196     /**
197      * Generates a Joiner ID from the Discerner.
198      *
199      * @param[out] aJoinerId   A reference to `Mac::ExtAddress` to output the generated Joiner ID.
200      *
201      */
202     void GenerateJoinerId(Mac::ExtAddress &aJoinerId) const;
203 
204     /**
205      * Indicates whether a given Joiner ID matches the Discerner.
206      *
207      * @param[in] aJoinerId  A Joiner ID to match with the Discerner.
208      *
209      * @returns TRUE if the Joiner ID matches the Discerner, FALSE otherwise.
210      *
211      */
212     bool Matches(const Mac::ExtAddress &aJoinerId) const;
213 
214     /**
215      * Overloads operator `==` to evaluate whether or not two Joiner Discerner instances are equal.
216      *
217      * @param[in]  aOther  The other Joiner Discerner to compare with.
218      *
219      * @retval TRUE   If the two are equal.
220      * @retval FALSE  If the two are not equal.
221      *
222      */
223     bool operator==(const JoinerDiscerner &aOther) const;
224 
225     /**
226      * Converts the Joiner Discerner to a string.
227      *
228      * @returns An `InfoString` representation of Joiner Discerner.
229      *
230      */
231     InfoString ToString(void) const;
232 
233 private:
GetMask(void) const234     uint64_t GetMask(void) const { return (static_cast<uint64_t>(1ULL) << mLength) - 1; }
235     void     CopyTo(Mac::ExtAddress &aExtAddress) const;
236 };
237 
238 /**
239  * Represents Steering Data (bloom filter).
240  *
241  */
242 class SteeringData : public otSteeringData
243 {
244 public:
245     static constexpr uint8_t kMaxLength = OT_STEERING_DATA_MAX_LENGTH; ///< Maximum Steering Data length (in bytes).
246 
247     /**
248      * Represents the hash bit index values for the bloom filter calculated from a Joiner ID.
249      *
250      * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI.
251      *
252      */
253     struct HashBitIndexes
254     {
255         static constexpr uint8_t kNumIndexes = 2; ///< Number of hash bit indexes.
256 
257         uint16_t mIndex[kNumIndexes]; ///< The hash bit index array.
258     };
259 
260     /**
261      * Initializes the Steering Data and clears the bloom filter.
262      *
263      * @param[in]  aLength   The Steering Data length (in bytes) - MUST be smaller than or equal to `kMaxLength`.
264      *
265      */
266     void Init(uint8_t aLength = kMaxLength);
267 
268     /**
269      * Clears the bloom filter (all bits are cleared and no Joiner Id is accepted)..
270      *
271      * The Steering Data length (bloom filter length) is set to one byte with all bits cleared.
272      *
273      */
Clear(void)274     void Clear(void) { Init(1); }
275 
276     /**
277      * Sets the bloom filter to permit all Joiner IDs.
278      *
279      * To permit all Joiner IDs, The Steering Data length (bloom filter length) is set to one byte with all bits set.
280      *
281      */
282     void SetToPermitAllJoiners(void);
283 
284     /**
285      * Returns the Steering Data length (in bytes).
286      *
287      * @returns The Steering Data length (in bytes).
288      *
289      */
GetLength(void) const290     uint8_t GetLength(void) const { return mLength; }
291 
292     /**
293      * Gets the Steering Data buffer (bloom filter).
294      *
295      * @returns A pointer to the Steering Data buffer.
296      *
297      */
GetData(void) const298     const uint8_t *GetData(void) const { return m8; }
299 
300     /**
301      * Gets the Steering Data buffer (bloom filter).
302      *
303      * @returns A pointer to the Steering Data buffer.
304      *
305      */
GetData(void)306     uint8_t *GetData(void) { return m8; }
307 
308     /**
309      * Updates the bloom filter adding the given Joiner ID.
310      *
311      * @param[in]  aJoinerId  The Joiner ID to add to bloom filter.
312      *
313      */
314     void UpdateBloomFilter(const Mac::ExtAddress &aJoinerId);
315 
316     /**
317      * Updates the bloom filter adding a given Joiner Discerner.
318      *
319      * @param[in]  aDiscerner  The Joiner Discerner to add to bloom filter.
320      *
321      */
322     void UpdateBloomFilter(const JoinerDiscerner &aDiscerner);
323 
324     /**
325      * Indicates whether the bloom filter is empty (all the bits are cleared).
326      *
327      * @returns TRUE if the bloom filter is empty, FALSE otherwise.
328      *
329      */
IsEmpty(void) const330     bool IsEmpty(void) const { return DoesAllMatch(0); }
331 
332     /**
333      * Indicates whether the bloom filter permits all Joiner IDs (all the bits are set).
334      *
335      * @returns TRUE if the bloom filter permits all Joiners IDs, FALSE otherwise.
336      *
337      */
PermitsAllJoiners(void) const338     bool PermitsAllJoiners(void) const { return (mLength > 0) && DoesAllMatch(kPermitAll); }
339 
340     /**
341      * Indicates whether the bloom filter contains a given Joiner ID.
342      *
343      * @param[in] aJoinerId  A Joiner ID.
344      *
345      * @returns TRUE if the bloom filter contains @p aJoinerId, FALSE otherwise.
346      *
347      */
348     bool Contains(const Mac::ExtAddress &aJoinerId) const;
349 
350     /**
351      * Indicates whether the bloom filter contains a given Joiner Discerner.
352      *
353      * @param[in] aDiscerner   A Joiner Discerner.
354      *
355      * @returns TRUE if the bloom filter contains @p aDiscerner, FALSE otherwise.
356      *
357      */
358     bool Contains(const JoinerDiscerner &aDiscerner) const;
359 
360     /**
361      * Indicates whether the bloom filter contains the hash bit indexes (derived from a Joiner ID).
362      *
363      * @param[in]  aIndexes   A hash bit index structure (derived from a Joiner ID).
364      *
365      * @returns TRUE if the bloom filter contains the Joiner ID mapping to @p aIndexes, FALSE otherwise.
366      *
367      */
368     bool Contains(const HashBitIndexes &aIndexes) const;
369 
370     /**
371      * Calculates the bloom filter hash bit indexes from a given Joiner ID.
372      *
373      * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI.
374      *
375      * @param[in]  aJoinerId  The Joiner ID to calculate the hash bit indexes.
376      * @param[out] aIndexes   A reference to a `HashBitIndexes` structure to output the calculated index values.
377      *
378      */
379     static void CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes);
380 
381     /**
382      * Calculates the bloom filter hash bit indexes from a given Joiner Discerner.
383      *
384      * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI.
385      *
386      * @param[in]  aDiscerner     The Joiner Discerner to calculate the hash bit indexes.
387      * @param[out] aIndexes       A reference to a `HashBitIndexes` structure to output the calculated index values.
388      *
389      */
390     static void CalculateHashBitIndexes(const JoinerDiscerner &aDiscerner, HashBitIndexes &aIndexes);
391 
392 private:
393     static constexpr uint8_t kPermitAll = 0xff;
394 
GetNumBits(void) const395     uint8_t GetNumBits(void) const { return (mLength * kBitsPerByte); }
396 
BitIndex(uint8_t aBit) const397     uint8_t BitIndex(uint8_t aBit) const { return (mLength - 1 - (aBit / kBitsPerByte)); }
BitFlag(uint8_t aBit) const398     uint8_t BitFlag(uint8_t aBit) const { return static_cast<uint8_t>(1U << (aBit % kBitsPerByte)); }
399 
GetBit(uint8_t aBit) const400     bool GetBit(uint8_t aBit) const { return (m8[BitIndex(aBit)] & BitFlag(aBit)) != 0; }
SetBit(uint8_t aBit)401     void SetBit(uint8_t aBit) { m8[BitIndex(aBit)] |= BitFlag(aBit); }
ClearBit(uint8_t aBit)402     void ClearBit(uint8_t aBit) { m8[BitIndex(aBit)] &= ~BitFlag(aBit); }
403 
404     bool DoesAllMatch(uint8_t aMatch) const;
405     void UpdateBloomFilter(const HashBitIndexes &aIndexes);
406 };
407 
408 /**
409  * Represents a Commissioning Dataset.
410  *
411  */
412 class CommissioningDataset : public otCommissioningDataset, public Clearable<CommissioningDataset>
413 {
414 public:
415     /**
416      * Indicates whether or not the Border Router RLOC16 Locator is set in the Dataset.
417      *
418      * @returns TRUE if Border Router RLOC16 Locator is set, FALSE otherwise.
419      *
420      */
IsLocatorSet(void) const421     bool IsLocatorSet(void) const { return mIsLocatorSet; }
422 
423     /**
424      * Gets the Border Router RLOC16 Locator in the Dataset.
425      *
426      * MUST be used when Locator is set in the Dataset, otherwise its behavior is undefined.
427      *
428      * @returns The Border Router RLOC16 Locator in the Dataset.
429      *
430      */
GetLocator(void) const431     uint16_t GetLocator(void) const { return mLocator; }
432 
433     /**
434      * Sets the Border Router RLOCG16 Locator in the Dataset.
435      *
436      * @param[in] aLocator  A Locator.
437      *
438      */
SetLocator(uint16_t aLocator)439     void SetLocator(uint16_t aLocator)
440     {
441         mIsLocatorSet = true;
442         mLocator      = aLocator;
443     }
444 
445     /**
446      * Indicates whether or not the Session ID is set in the Dataset.
447      *
448      * @returns TRUE if Session ID is set, FALSE otherwise.
449      *
450      */
IsSessionIdSet(void) const451     bool IsSessionIdSet(void) const { return mIsSessionIdSet; }
452 
453     /**
454      * Gets the Session ID in the Dataset.
455      *
456      * MUST be used when Session ID is set in the Dataset, otherwise its behavior is undefined.
457      *
458      * @returns The Session ID in the Dataset.
459      *
460      */
GetSessionId(void) const461     uint16_t GetSessionId(void) const { return mSessionId; }
462 
463     /**
464      * Sets the Session ID in the Dataset.
465      *
466      * @param[in] aSessionId  The Session ID.
467      *
468      */
SetSessionId(uint16_t aSessionId)469     void SetSessionId(uint16_t aSessionId)
470     {
471         mIsSessionIdSet = true;
472         mSessionId      = aSessionId;
473     }
474 
475     /**
476      * Indicates whether or not the Steering Data is set in the Dataset.
477      *
478      * @returns TRUE if Steering Data is set, FALSE otherwise.
479      *
480      */
IsSteeringDataSet(void) const481     bool IsSteeringDataSet(void) const { return mIsSteeringDataSet; }
482 
483     /**
484      * Gets the Steering Data in the Dataset.
485      *
486      * MUST be used when Steering Data is set in the Dataset, otherwise its behavior is undefined.
487      *
488      * @returns The Steering Data in the Dataset.
489      *
490      */
GetSteeringData(void) const491     const SteeringData &GetSteeringData(void) const { return static_cast<const SteeringData &>(mSteeringData); }
492 
493     /**
494      * Returns a reference to the Steering Data in the Dataset to be updated by caller.
495      *
496      * @returns A reference to the Steering Data in the Dataset.
497      *
498      */
UpdateSteeringData(void)499     SteeringData &UpdateSteeringData(void)
500     {
501         mIsSteeringDataSet = true;
502         return static_cast<SteeringData &>(mSteeringData);
503     }
504 
505     /**
506      * Indicates whether or not the Joiner UDP port is set in the Dataset.
507      *
508      * @returns TRUE if Joiner UDP port is set, FALSE otherwise.
509      *
510      */
IsJoinerUdpPortSet(void) const511     bool IsJoinerUdpPortSet(void) const { return mIsJoinerUdpPortSet; }
512 
513     /**
514      * Gets the Joiner UDP port in the Dataset.
515      *
516      * MUST be used when Joiner UDP port is set in the Dataset, otherwise its behavior is undefined.
517      *
518      * @returns The Joiner UDP port in the Dataset.
519      *
520      */
GetJoinerUdpPort(void) const521     uint16_t GetJoinerUdpPort(void) const { return mJoinerUdpPort; }
522 
523     /**
524      * Sets the Joiner UDP Port in the Dataset.
525      *
526      * @param[in] aJoinerUdpPort  The Joiner UDP Port.
527      *
528      */
SetJoinerUdpPort(uint16_t aJoinerUdpPort)529     void SetJoinerUdpPort(uint16_t aJoinerUdpPort)
530     {
531         mIsJoinerUdpPortSet = true;
532         mJoinerUdpPort      = aJoinerUdpPort;
533     }
534 };
535 
536 /**
537  * Generates PSKc.
538  *
539  * PSKc is used to establish the Commissioner Session.
540  *
541  * @param[in]  aPassPhrase   The commissioning passphrase.
542  * @param[in]  aNetworkName  The network name for PSKc computation.
543  * @param[in]  aExtPanId     The extended PAN ID for PSKc computation.
544  * @param[out] aPskc         A reference to a PSKc where the generated PSKc will be placed.
545  *
546  * @retval kErrorNone          Successfully generate PSKc.
547  * @retval kErrorInvalidArgs   If the length of passphrase is out of range.
548  *
549  */
550 Error GeneratePskc(const char          *aPassPhrase,
551                    const NetworkName   &aNetworkName,
552                    const ExtendedPanId &aExtPanId,
553                    Pskc                &aPskc);
554 
555 /**
556  * Computes the Joiner ID from a factory-assigned IEEE EUI-64.
557  *
558  * @param[in]   aEui64     The factory-assigned IEEE EUI-64.
559  * @param[out]  aJoinerId  The Joiner ID.
560  *
561  */
562 void ComputeJoinerId(const Mac::ExtAddress &aEui64, Mac::ExtAddress &aJoinerId);
563 
564 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
565 /**
566  * Emits a log message indicating an error during a MeshCoP action.
567  *
568  * Note that log message is emitted only if there is an error, i.e. @p aError is not `kErrorNone`. The log
569  * message will have the format "Failed to {aActionText} : {ErrorString}".
570  *
571  * @param[in] aActionText   A string representing the failed action.
572  * @param[in] aError        The error in sending the message.
573  *
574  */
575 void LogError(const char *aActionText, Error aError);
576 #else
LogError(const char *,Error)577 inline void LogError(const char *, Error) {}
578 #endif
579 
580 } // namespace MeshCoP
581 
582 DefineCoreType(otJoinerPskd, MeshCoP::JoinerPskd);
583 DefineCoreType(otJoinerDiscerner, MeshCoP::JoinerDiscerner);
584 DefineCoreType(otSteeringData, MeshCoP::SteeringData);
585 DefineCoreType(otCommissioningDataset, MeshCoP::CommissioningDataset);
586 
587 } // namespace ot
588 
589 #endif // MESHCOP_HPP_
590