blob: 0de1047029d9c1772815f78c3c80b69099f5242e [file] [log] [blame]
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for MeshCoP.
*
*/
#ifndef MESHCOP_HPP_
#define MESHCOP_HPP_
#include "openthread-core-config.h"
#include <limits.h>
#include <openthread/commissioner.h>
#include <openthread/instance.h>
#include <openthread/joiner.h>
#include "coap/coap.hpp"
#include "common/as_core_type.hpp"
#include "common/clearable.hpp"
#include "common/equatable.hpp"
#include "common/log.hpp"
#include "common/message.hpp"
#include "common/string.hpp"
#include "mac/mac_types.hpp"
#include "meshcop/meshcop_tlvs.hpp"
namespace ot {
class ThreadNetif;
namespace MeshCoP {
/**
* This type represents a Joiner PSKd.
*
*/
class JoinerPskd : public otJoinerPskd, public Clearable<JoinerPskd>, public Unequatable<JoinerPskd>
{
public:
static constexpr uint8_t kMinLength = 6; ///< Min PSKd string length (excludes null char)
static constexpr uint8_t kMaxLength = OT_JOINER_MAX_PSKD_LENGTH; ///< Max PSKd string length (excludes null char)
/**
* This method indicates whether the PSKd if well-formed and valid.
*
* Per Thread specification, a Joining Device Credential is encoded as uppercase alphanumeric characters
* (base32-thread: 0-9, A-Z excluding I, O, Q, and Z for readability) with a minimum length of 6 such characters
* and a maximum length of 32 such characters.
*
* @returns TRUE if the PSKd is valid, FALSE otherwise.
*
*/
bool IsValid(void) const { return IsPskdValid(m8); }
/**
* This method sets the joiner PSKd from a given C string.
*
* @param[in] aPskdString A pointer to the PSKd C string array.
*
* @retval kErrorNone The PSKd was updated successfully.
* @retval kErrorInvalidArgs The given PSKd C string is not valid.
*
*/
Error SetFrom(const char *aPskdString);
/**
* This method gets the PSKd as a null terminated C string.
*
* This method must be used after the PSKd is validated, otherwise its behavior is undefined.
*
* @returns The PSKd as a C string.
*
*/
const char *GetAsCString(void) const { return m8; }
/**
* This method gets the PSKd string length.
*
* This method must be used after the PSKd is validated, otherwise its behavior is undefined.
*
* @returns The PSKd string length.
*
*/
uint8_t GetLength(void) const { return static_cast<uint8_t>(StringLength(m8, kMaxLength + 1)); }
/**
* This method overloads operator `==` to evaluate whether or not two PSKds are equal.
*
* @param[in] aOther The other PSKd to compare with.
*
* @retval TRUE If the two are equal.
* @retval FALSE If the two are not equal.
*
*/
bool operator==(const JoinerPskd &aOther) const;
/**
* This static method indicates whether a given PSKd string if well-formed and valid.
*
* @param[in] aPskdString A pointer to a PSKd string array.
*
* @sa IsValid()
*
* @returns TRUE if @p aPskdString is valid, FALSE otherwise.
*
*/
static bool IsPskdValid(const char *aPskdString);
};
/**
* This type represents a Joiner Discerner.
*
*/
class JoinerDiscerner : public otJoinerDiscerner, public Unequatable<JoinerDiscerner>
{
friend class SteeringData;
public:
static constexpr uint8_t kMaxLength = OT_JOINER_MAX_DISCERNER_LENGTH; ///< Max length of a Discerner in bits.
static constexpr uint16_t kInfoStringSize = 45; ///< Size of `InfoString` to use with `ToString()
/**
* This type defines the fixed-length `String` object returned from `ToString()`.
*
*/
typedef String<kInfoStringSize> InfoString;
/**
* This method clears the Joiner Discerner.
*
*/
void Clear(void) { mLength = 0; }
/**
* This method indicates whether the Joiner Discerner is empty (no value set).
*
* @returns TRUE if empty, FALSE otherwise.
*
*/
bool IsEmpty(void) const { return mLength == 0; }
/**
* This method gets the Joiner Discerner's value.
*
* @returns The Joiner Discerner value.
*
*/
uint64_t GetValue(void) const { return mValue; }
/**
* This method gets the Joiner Discerner's length (in bits).
*
* @return The Joiner Discerner length.
*
*/
uint8_t GetLength(void) const { return mLength; }
/**
* This method indicates whether the Joiner Discerner is valid (i.e. it not empty and its length is within
* valid range).
*
* @returns TRUE if Joiner Discerner is valid, FALSE otherwise.
*
*/
bool IsValid(void) const { return (0 < mLength) && (mLength <= kMaxLength); }
/**
* This method generates a Joiner ID from the Discerner.
*
* @param[out] aJoinerId A reference to `Mac::ExtAddress` to output the generated Joiner ID.
*
*/
void GenerateJoinerId(Mac::ExtAddress &aJoinerId) const;
/**
* This method indicates whether a given Joiner ID matches the Discerner.
*
* @param[in] aJoinerId A Joiner ID to match with the Discerner.
*
* @returns TRUE if the Joiner ID matches the Discerner, FALSE otherwise.
*
*/
bool Matches(const Mac::ExtAddress &aJoinerId) const;
/**
* This method overloads operator `==` to evaluate whether or not two Joiner Discerner instances are equal.
*
* @param[in] aOther The other Joiner Discerner to compare with.
*
* @retval TRUE If the two are equal.
* @retval FALSE If the two are not equal.
*
*/
bool operator==(const JoinerDiscerner &aOther) const;
/**
* This method converts the Joiner Discerner to a string.
*
* @returns An `InfoString` representation of Joiner Discerner.
*
*/
InfoString ToString(void) const;
private:
uint64_t GetMask(void) const { return (static_cast<uint64_t>(1ULL) << mLength) - 1; }
void CopyTo(Mac::ExtAddress &aExtAddress) const;
};
/**
* This type represents Steering Data (bloom filter).
*
*/
class SteeringData : public otSteeringData
{
public:
static constexpr uint8_t kMaxLength = OT_STEERING_DATA_MAX_LENGTH; ///< Maximum Steering Data length (in bytes).
/**
* This structure represents the hash bit index values for the bloom filter calculated from a Joiner ID.
*
* The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI.
*
*/
struct HashBitIndexes
{
static constexpr uint8_t kNumIndexes = 2; ///< Number of hash bit indexes.
uint16_t mIndex[kNumIndexes]; ///< The hash bit index array.
};
/**
* This method initializes the Steering Data and clears the bloom filter.
*
* @param[in] aLength The Steering Data length (in bytes) - MUST be smaller than or equal to `kMaxLength`.
*
*/
void Init(uint8_t aLength = kMaxLength);
/**
* This method clears the bloom filter (all bits are cleared and no Joiner Id is accepted)..
*
* The Steering Data length (bloom filter length) is set to one byte with all bits cleared.
*
*/
void Clear(void) { Init(1); }
/**
* This method sets the bloom filter to permit all Joiner IDs.
*
* To permit all Joiner IDs, The Steering Data length (bloom filter length) is set to one byte with all bits set.
*
*/
void SetToPermitAllJoiners(void);
/**
* This method returns the Steering Data length (in bytes).
*
* @returns The Steering Data length (in bytes).
*
*/
uint8_t GetLength(void) const { return mLength; }
/**
* This method gets the Steering Data buffer (bloom filter).
*
* @returns A pointer to the Steering Data buffer.
*
*/
const uint8_t *GetData(void) const { return m8; }
/**
* This method gets the Steering Data buffer (bloom filter).
*
* @returns A pointer to the Steering Data buffer.
*
*/
uint8_t *GetData(void) { return m8; }
/**
* This method updates the bloom filter adding the given Joiner ID.
*
* @param[in] aJoinerId The Joiner ID to add to bloom filter.
*
*/
void UpdateBloomFilter(const Mac::ExtAddress &aJoinerId);
/**
* This method updates the bloom filter adding a given Joiner Discerner.
*
* @param[in] aDiscerner The Joiner Discerner to add to bloom filter.
*
*/
void UpdateBloomFilter(const JoinerDiscerner &aDiscerner);
/**
* This method indicates whether the bloom filter is empty (all the bits are cleared).
*
* @returns TRUE if the bloom filter is empty, FALSE otherwise.
*
*/
bool IsEmpty(void) const { return DoesAllMatch(0); }
/**
* This method indicates whether the bloom filter permits all Joiner IDs (all the bits are set).
*
* @returns TRUE if the bloom filter permits all Joiners IDs, FALSE otherwise.
*
*/
bool PermitsAllJoiners(void) const { return (mLength > 0) && DoesAllMatch(kPermitAll); }
/**
* This method indicates whether the bloom filter contains a given Joiner ID.
*
* @param[in] aJoinerId A Joiner ID.
*
* @returns TRUE if the bloom filter contains @p aJoinerId, FALSE otherwise.
*
*/
bool Contains(const Mac::ExtAddress &aJoinerId) const;
/**
* This method indicates whether the bloom filter contains a given Joiner Discerner.
*
* @param[in] aDiscerner A Joiner Discerner.
*
* @returns TRUE if the bloom filter contains @p aDiscerner, FALSE otherwise.
*
*/
bool Contains(const JoinerDiscerner &aDiscerner) const;
/**
* This method indicates whether the bloom filter contains the hash bit indexes (derived from a Joiner ID).
*
* @param[in] aIndexes A hash bit index structure (derived from a Joiner ID).
*
* @returns TRUE if the bloom filter contains the Joiner ID mapping to @p aIndexes, FALSE otherwise.
*
*/
bool Contains(const HashBitIndexes &aIndexes) const;
/**
* This static method calculates the bloom filter hash bit indexes from a given Joiner ID.
*
* The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI.
*
* @param[in] aJoinerId The Joiner ID to calculate the hash bit indexes.
* @param[out] aIndexes A reference to a `HashBitIndexes` structure to output the calculated index values.
*
*/
static void CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes);
/**
* This static method calculates the bloom filter hash bit indexes from a given Joiner Discerner.
*
* The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI.
*
* @param[in] aDiscerner The Joiner Discerner to calculate the hash bit indexes.
* @param[out] aIndexes A reference to a `HashBitIndexes` structure to output the calculated index values.
*
*/
static void CalculateHashBitIndexes(const JoinerDiscerner &aDiscerner, HashBitIndexes &aIndexes);
private:
static constexpr uint8_t kPermitAll = 0xff;
uint8_t GetNumBits(void) const { return (mLength * CHAR_BIT); }
uint8_t BitIndex(uint8_t aBit) const { return (mLength - 1 - (aBit / CHAR_BIT)); }
uint8_t BitFlag(uint8_t aBit) const { return static_cast<uint8_t>(1U << (aBit % CHAR_BIT)); }
bool GetBit(uint8_t aBit) const { return (m8[BitIndex(aBit)] & BitFlag(aBit)) != 0; }
void SetBit(uint8_t aBit) { m8[BitIndex(aBit)] |= BitFlag(aBit); }
void ClearBit(uint8_t aBit) { m8[BitIndex(aBit)] &= ~BitFlag(aBit); }
bool DoesAllMatch(uint8_t aMatch) const;
void UpdateBloomFilter(const HashBitIndexes &aIndexes);
};
/**
* This function generates PSKc.
*
* PSKc is used to establish the Commissioner Session.
*
* @param[in] aPassPhrase The commissioning passphrase.
* @param[in] aNetworkName The network name for PSKc computation.
* @param[in] aExtPanId The extended PAN ID for PSKc computation.
* @param[out] aPskc A reference to a PSKc where the generated PSKc will be placed.
*
* @retval kErrorNone Successfully generate PSKc.
* @retval kErrorInvalidArgs If the length of passphrase is out of range.
*
*/
Error GeneratePskc(const char * aPassPhrase,
const NetworkName & aNetworkName,
const ExtendedPanId &aExtPanId,
Pskc & aPskc);
/**
* This function computes the Joiner ID from a factory-assigned IEEE EUI-64.
*
* @param[in] aEui64 The factory-assigned IEEE EUI-64.
* @param[out] aJoinerId The Joiner ID.
*
*/
void ComputeJoinerId(const Mac::ExtAddress &aEui64, Mac::ExtAddress &aJoinerId);
/**
* This function gets the border agent RLOC.
*
* @param[in] aNetIf A reference to the thread interface.
* @param[out] aRloc Border agent RLOC.
*
* @retval kErrorNone Successfully got the Border Agent Rloc.
* @retval kErrorNotFound Border agent is not available.
*
*/
Error GetBorderAgentRloc(ThreadNetif &aNetIf, uint16_t &aRloc);
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
/**
* This function emits a log message indicating an error during a MeshCoP action.
*
* Note that log message is emitted only if there is an error, i.e. @p aError is not `kErrorNone`. The log
* message will have the format "Failed to {aActionText} : {ErrorString}".
*
* @param[in] aActionText A string representing the failed action.
* @param[in] aError The error in sending the message.
*
*/
void LogError(const char *aActionText, Error aError);
#else
inline void LogError(const char *, Error)
{
}
#endif
} // namespace MeshCoP
DefineCoreType(otJoinerPskd, MeshCoP::JoinerPskd);
DefineCoreType(otJoinerDiscerner, MeshCoP::JoinerDiscerner);
DefineCoreType(otSteeringData, MeshCoP::SteeringData);
} // namespace ot
#endif // MESHCOP_HPP_