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