/* * Author: Sven Gothel * Copyright (c) 2021 Gothel Software e.K. * Copyright (c) 2020 ZAFENA AB * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef BT_ADDRESS_HPP_ #define BT_ADDRESS_HPP_ #include #include #include #include #include #include #include using jau::EUI48; using jau::EUI48Sub; namespace direct_bt { /** * BT Core Spec v5.2: Vol 3, Part C Generic Access Profile (GAP): 15.1.1.1 Public Bluetooth address *
     * 1) BT public address used as BD_ADDR for BR/EDR physical channel is defined in Vol 2, Part B 1.2
     * - EUI-48 or MAC (6 octets)
     *
     * 2) BT public address used as BD_ADDR for the LE physical channel is defined in Vol 6, Part B 1.3
     *    BT Core Spec v5.2:  Vol 3, Part C Generic Access Profile (GAP): 15.1.1.2 Random Bluetooth address
     *
     * 3) BT random address used as BD_ADDR on the LE physical channel is defined in Vol 3, Part C 10.8
     * 
*/ enum class BDAddressType : uint8_t { /** Bluetooth BREDR address */ BDADDR_BREDR = 0x00, /** Bluetooth LE public address */ BDADDR_LE_PUBLIC = 0x01, /** Bluetooth LE random address, see {@link BLERandomAddressType} */ BDADDR_LE_RANDOM = 0x02, /** Undefined */ BDADDR_UNDEFINED = 0xff }; constexpr BDAddressType to_BDAddressType(const uint8_t v) noexcept { if( v <= 2 ) { return static_cast(v); } return BDAddressType::BDADDR_UNDEFINED; } constexpr uint8_t number(const BDAddressType rhs) noexcept { return static_cast(rhs); } std::string to_string(const BDAddressType type) noexcept; /** * BT Core Spec v5.2: Vol 6 LE, Part B Link Layer Specification: 1.3 Device Address *

* BT Core Spec v5.2: Vol 6 LE, Part B Link Layer Specification: 1.3.2 Random device Address *

*

* Table 1.2, address bits [47:46] *

*

* If {@link BDAddressType} is {@link BDAddressType::BDADDR_LE_RANDOM}, * its value shall be different than {@link BLERandomAddressType::UNDEFINED}. *

*

* If {@link BDAddressType} is not {@link BDAddressType::BDADDR_LE_RANDOM}, * its value shall be {@link BLERandomAddressType::UNDEFINED}. *

*/ enum class BLERandomAddressType : uint8_t { /** Non-resolvable private random device address 0b00 */ UNRESOLVABLE_PRIVAT = 0x00, /** * Resolvable private random device address 0b01. * * Requires Local Identity Resolving Key (IRK) or the Peer Identity Resolving Key (IRK). * * EUI48: 24 bits hash = ag(IRK, prand), 24 bits prand. */ RESOLVABLE_PRIVAT = 0x01, /** Reserved for future use 0b10 */ RESERVED = 0x02, /** Static public 'random' device address 0b11. Not changing between power-cycles. */ STATIC_PUBLIC = 0x03, /** Undefined, e.g. address not of type {@link BDAddressType::BDADDR_LE_RANDOM} */ UNDEFINED = 0xff }; constexpr uint8_t number(const BLERandomAddressType rhs) noexcept { return static_cast(rhs); } std::string to_string(const BLERandomAddressType type) noexcept; /** * HCI LE Address-Type is PUBLIC: 0x00, RANDOM: 0x01 *

* BT Core Spec v5.2: Vol 4, Part E Host Controller Interface (HCI) Functionality: *

     * > 7.8.5: LE Set Advertising Parameters command
     * -- Own_Address_Type: public: 0x00 (default), random: 0x01, resolvable-1: 0x02, resolvable-2: 0x03
     * > 7.8.10: LE Set Scan Parameters command
     * -- Own_Address_Type: public: 0x00 (default), random: 0x01, resolvable-1: 0x02, resolvable-2: 0x03
     * > 7.8.12: LE Create Connection command
     * -- Own_Address_Type: public: 0x00 (default), random: 0x01,
     *    Public Identity Address (resolvable-1, any not supporting LE_Set_Privacy_Mode command): 0x02,
     *    Random (static) Identity Address (resolvable-2, any not supporting LE_Set_Privacy_Mode command): 0x03
     * 
*

*/ enum class HCILEPeerAddressType : uint8_t { /** Public Device Address */ PUBLIC = 0x00, /** Random Device Address */ RANDOM = 0x01, /** Public Resolved Identity Address */ PUBLIC_IDENTITY = 0x02, /** Resolved Random (Static) Identity Address */ RANDOM_STATIC_IDENTITY = 0x03, UNDEFINED = 0xff /**< HCIADDR_UNDEFINED */ }; constexpr uint8_t number(const HCILEPeerAddressType rhs) noexcept { return static_cast(rhs); } BDAddressType to_BDAddressType(const HCILEPeerAddressType hciPeerAddrType) noexcept; std::string to_string(const HCILEPeerAddressType type) noexcept; enum class HCILEOwnAddressType : uint8_t { /** Public Device Address */ PUBLIC = 0x00, /** Random Device Address */ RANDOM = 0x01, /** Controller Resolved Private Address or Public Address */ RESOLVABLE_OR_PUBLIC = 0x02, /** Controller Resolved Private Address or Random Address */ RESOLVABLE_OR_RANDOM = 0x03, UNDEFINED = 0xff }; constexpr uint8_t number(const HCILEOwnAddressType rhs) noexcept { return static_cast(rhs); } BDAddressType to_BDAddressType(const HCILEOwnAddressType hciOwnAddrType) noexcept; HCILEOwnAddressType to_HCILEOwnAddressType(const BDAddressType addrType) noexcept; std::string to_string(const HCILEOwnAddressType type) noexcept; /** * Unique Bluetooth EUI48 address and ::BDAddressType tuple. *

* Bluetooth EUI48 address itself is not unique as it requires the ::BDAddressType bits.
* E.g. there could be two devices with the same EUI48 address, one using ::BDAddressType::BDADDR_LE_PUBLIC * and one using ::BDAddressType::BDADDR_LE_RANDOM being a ::BLERandomAddressType::RESOLVABLE_PRIVAT. *

*/ class BDAddressAndType { public: /** Using EUI48::ANY_DEVICE and ::BDAddressType::BDADDR_BREDR to match any BREDR device. */ static const BDAddressAndType ANY_BREDR_DEVICE; /** * Using EUI48::ANY_DEVICE and ::BDAddressType::BDADDR_UNDEFINED to match any device.
* This constant is suitable to {@link #matches(BDAddressAndType) any device. */ static const BDAddressAndType ANY_DEVICE; jau::EUI48 address; BDAddressType type; private: jau::relaxed_atomic_size_t hash = 0; // default 0, cache public: BDAddressAndType(const jau::EUI48 & address_, BDAddressType type_) : address(address_), type(type_) {} constexpr BDAddressAndType() noexcept : address(), type{BDAddressType::BDADDR_UNDEFINED} { } BDAddressAndType(const BDAddressAndType &o) noexcept : address(o.address), type(o.type) { } BDAddressAndType(BDAddressAndType &&o) noexcept { address = std::move(o.address); type = std::move(o.type); } constexpr BDAddressAndType& operator=(const BDAddressAndType &o) noexcept { address = o.address; type = o.type; return *this; } BDAddressAndType& operator=(BDAddressAndType &&o) noexcept { address = std::move(o.address); type = std::move(o.type); return *this; } /** * Returns true if the BDAddressType is a LE address type. */ constexpr bool isLEAddress() const noexcept { return BDAddressType::BDADDR_LE_PUBLIC == type || BDAddressType::BDADDR_LE_RANDOM == type; } /** * Returns true if the BDAddressType is a BREDR address type. */ constexpr bool isBREDRAddress() const noexcept { return BDAddressType::BDADDR_BREDR == type; } /** * Returns the BLERandomAddressType. *

* If ::BDAddressType is ::BDAddressType::BDADDR_LE_RANDOM, * method shall return a valid value other than ::BLERandomAddressType::UNDEFINED. *

*

* If BDAddressType is not ::BDAddressType::BDADDR_LE_RANDOM, * method shall return ::BLERandomAddressType::UNDEFINED. *

* @since 2.2.0 */ static BLERandomAddressType getBLERandomAddressType(const jau::EUI48& address, const BDAddressType addressType) noexcept; /** * Returns the BLERandomAddressType. *

* If type is ::BDAddressType::BDADDR_LE_RANDOM}, * method shall return a valid value other than ::BLERandomAddressType::UNDEFINED. *

*

* If type is not ::BDAddressType::BDADDR_LE_RANDOM, * method shall return ::BLERandomAddressType::UNDEFINED. *

* @since 2.0.0 */ BLERandomAddressType getBLERandomAddressType() const noexcept { return getBLERandomAddressType(address, type); } /** * Returns true if both devices match, i.e. equal address * and equal type or at least one type is {@link BDAddressType#BDADDR_UNDEFINED}. */ bool matches(const BDAddressAndType & o) const noexcept { if(this == &o) { return true; } return address == o.address && ( type == o.type || BDAddressType::BDADDR_UNDEFINED == type || BDAddressType::BDADDR_UNDEFINED == o.type ); } /** * Implementation uses a lock-free volatile cache. */ std::size_t hash_code() const noexcept { std::size_t h = hash; if( 0 == h ) { // 31 * x == (x << 5) - x h = 31 + address.hash_code(); h = ((h << 5) - h) + number(type); const_cast(this)->hash = h; } return h; } /** * Method clears the cached hash value. * @see #clear() */ void clearHash() { hash = 0; } /** * Method clears the underlying byte array {@link #b} and cached hash value. * @see #clearHash() */ void clear() { hash = 0; address.clear(); type = BDAddressType::BDADDR_UNDEFINED; } std::string toString() const noexcept; }; inline bool operator==(const BDAddressAndType& lhs, const BDAddressAndType& rhs) noexcept { if( &lhs == &rhs ) { return true; } return lhs.address == rhs.address && lhs.type == rhs.type; } inline bool operator!=(const BDAddressAndType& lhs, const BDAddressAndType& rhs) noexcept { return !(lhs == rhs); } inline std::string to_string(const BDAddressAndType& a) noexcept { return a.toString(); } } // namespace direct_bt // injecting specialization of std::hash to namespace std of our types above namespace std { template<> struct hash { std::size_t operator()(direct_bt::BDAddressAndType const& a) const noexcept { return a.hash_code(); } }; } #endif /* BT_ADDRESS_HPP_ */