diff options
-rw-r--r-- | api/direct_bt/BTAdapter.hpp | 4 | ||||
-rw-r--r-- | api/direct_bt/BTManager.hpp | 2 | ||||
-rw-r--r-- | api/direct_bt/MgmtTypes.hpp | 28 | ||||
-rw-r--r-- | examples/dbt_scanner10.cpp | 7 | ||||
-rw-r--r-- | src/direct_bt/BTAdapter.cpp | 65 | ||||
-rw-r--r-- | src/direct_bt/BTManager.cpp | 8 |
6 files changed, 113 insertions, 1 deletions
diff --git a/api/direct_bt/BTAdapter.hpp b/api/direct_bt/BTAdapter.hpp index 4370d791..308f2457 100644 --- a/api/direct_bt/BTAdapter.hpp +++ b/api/direct_bt/BTAdapter.hpp @@ -349,6 +349,7 @@ namespace direct_bt { */ BDAddressAndType visibleAddressAndType; HCILEOwnAddressType visibleMACType; + MgmtIdentityResolvingKeyInfo privacyIRK; public: typedef jau::nsize_t size_type; @@ -527,6 +528,7 @@ namespace direct_bt { void mgmtEvPairDeviceCompleteMgmt(const MgmtEvent& e) noexcept; void mgmtEvNewLongTermKeyMgmt(const MgmtEvent& e) noexcept; void mgmtEvNewLinkKeyMgmt(const MgmtEvent& e) noexcept; + void mgmtEvNewIdentityResolvingKeyMgmt(const MgmtEvent& e) noexcept; void mgmtEvHCIAnyHCI(const MgmtEvent& e) noexcept; void mgmtEvDeviceDiscoveringHCI(const MgmtEvent& e) noexcept; @@ -745,6 +747,8 @@ namespace direct_bt { */ bool setPowered(const bool power_on) noexcept; + HCIStatusCode setPrivacy(const bool enable) noexcept; + /** * Returns whether Secure Connections (SC) is enabled. * @see setSecureConnections() diff --git a/api/direct_bt/BTManager.hpp b/api/direct_bt/BTManager.hpp index 2bbcc55e..3a80621b 100644 --- a/api/direct_bt/BTManager.hpp +++ b/api/direct_bt/BTManager.hpp @@ -420,6 +420,8 @@ namespace direct_bt { HCIStatusCode initializeAdapter(AdapterInfo& adapterInfo, const uint16_t dev_id, const BTMode btMode, const bool powerOn) noexcept; + HCIStatusCode setPrivacy(const uint16_t dev_id, const uint8_t privacy, const jau::uint128_t& irk, AdapterSetting& current_settings) noexcept; + /** * Read default connection parameter for given adapter to the kernel. * diff --git a/api/direct_bt/MgmtTypes.hpp b/api/direct_bt/MgmtTypes.hpp index 444e3035..9329edd3 100644 --- a/api/direct_bt/MgmtTypes.hpp +++ b/api/direct_bt/MgmtTypes.hpp @@ -826,6 +826,34 @@ namespace direct_bt { }; /** + * uint8_t privacy 0x00 disabled, 0x01 always on (discoverable + pairing), 0x02 limited (not when discoverable, bondable) + * jau::uint128_t irk Identity Resolving Key + */ + class MgmtSetPrivacyCmd : public MgmtCommand + { + protected: + std::string valueString() const noexcept override { + const jau::uint128_t& irk = getIdentityResolvingKey(); + return "param[size "+std::to_string(getParamSize())+", data[privacy "+std::to_string(getPrivacy())+ + ", irk "+jau::bytesHexString(irk.data, 0, sizeof(irk), true /* lsbFirst */)+"]]"; + } + + public: + MgmtSetPrivacyCmd(const uint16_t dev_id, const uint8_t privacy, const jau::uint128_t& irk) + : MgmtCommand(Opcode::SET_PRIVACY, dev_id, 1 + sizeof(irk)) + { + pdu.put_uint8_nc(MGMT_HEADER_SIZE, privacy); + memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+1), &irk, sizeof(irk)); + } + + uint8_t getPrivacy() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE); } + + const jau::uint128_t& getIdentityResolvingKey() const { + return *reinterpret_cast<const jau::uint128_t *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) ); + } + }; + + /** * mgmt_addr_info { EUI48, uint8_t type }, */ class MgmtGetConnectionInfoCmd : public MgmtCmdAdressInfoMeta diff --git a/examples/dbt_scanner10.cpp b/examples/dbt_scanner10.cpp index bceb21ef..15c4ddd0 100644 --- a/examples/dbt_scanner10.cpp +++ b/examples/dbt_scanner10.cpp @@ -113,6 +113,7 @@ static uint64_t timestamp_t0; static EUI48 useAdapter = EUI48::ALL_DEVICE; static BTMode btMode = BTMode::DUAL; +static bool use_privacy = false; static DiscoveryPolicy discoveryPolicy = DiscoveryPolicy::PAUSE_CONNECTED_UNTIL_READY; // default value static bool le_scan_active = true; // default value @@ -637,6 +638,7 @@ static bool initAdapter(std::shared_ptr<BTAdapter>& adapter) { to_string(status).c_str(), adapter->toString().c_str()); return false; } + adapter->setPrivacy(use_privacy); } if( !adapter->setPowered( true ) ) { fprintf_td(stderr, "initAdapter: Adapter power-on failed:: %s\n", adapter->toString().c_str()); @@ -768,6 +770,8 @@ int main(int argc, char *argv[]) btMode = to_BTMode(argv[++i]); } else if( !strcmp("-adapter", argv[i]) && argc > (i+1) ) { useAdapter = EUI48( std::string(argv[++i]) ); + } else if( !strcmp("-privacy", argv[i]) ) { + use_privacy = true; } else if( !strcmp("-dev", argv[i]) && argc > (i+1) ) { std::string addrOrNameSub = std::string(argv[++i]); BTDeviceRegistry::addToWaitForDevices( addrOrNameSub ); @@ -819,6 +823,7 @@ int main(int argc, char *argv[]) "[-scanPassive] " "[-resetEachCon connectionCount] " "[-adapter <adapter_address>] " + "[-privacy] " "(-dev <device_[address|name]_sub>)* " "(-seclevel <device_[address|name]_sub> <int_sec_level>)* " "(-iocap <device_[address|name]_sub> <int_iocap>)* " @@ -840,7 +845,7 @@ int main(int argc, char *argv[]) fprintf_td(stderr, "REMOVE_DEVICE %d\n", REMOVE_DEVICE); fprintf_td(stderr, "SHOW_UPDATE_EVENTS %d\n", SHOW_UPDATE_EVENTS); fprintf_td(stderr, "QUIET %d\n", QUIET); - fprintf_td(stderr, "adapter %s\n", useAdapter.toString().c_str()); + fprintf_td(stderr, "adapter %s, privacy %d\n", useAdapter.toString().c_str(), use_privacy); fprintf_td(stderr, "btmode %s\n", to_string(btMode).c_str()); fprintf_td(stderr, "discoveryPolicy %s\n", to_string(discoveryPolicy).c_str()); fprintf_td(stderr, "scanActive %s\n", to_string(le_scan_active).c_str()); diff --git a/src/direct_bt/BTAdapter.cpp b/src/direct_bt/BTAdapter.cpp index 5dc5670d..3fd69ba3 100644 --- a/src/direct_bt/BTAdapter.cpp +++ b/src/direct_bt/BTAdapter.cpp @@ -30,6 +30,7 @@ #include <cstdio> #include <algorithm> +#include <random> #include <jau/debug.hpp> @@ -331,6 +332,7 @@ bool BTAdapter::enableListening(const bool enable) noexcept { ok = mgmt->addMgmtEventCallback(dev_id, MgmtEvent::Opcode::PAIR_DEVICE_COMPLETE, jau::bind_member(this, &BTAdapter::mgmtEvPairDeviceCompleteMgmt)) && ok; ok = mgmt->addMgmtEventCallback(dev_id, MgmtEvent::Opcode::NEW_LONG_TERM_KEY, jau::bind_member(this, &BTAdapter::mgmtEvNewLongTermKeyMgmt)) && ok; ok = mgmt->addMgmtEventCallback(dev_id, MgmtEvent::Opcode::NEW_LINK_KEY, jau::bind_member(this, &BTAdapter::mgmtEvNewLinkKeyMgmt)) && ok; + ok = mgmt->addMgmtEventCallback(dev_id, MgmtEvent::Opcode::NEW_IRK, jau::bind_member(this, &BTAdapter::mgmtEvNewIdentityResolvingKeyMgmt)) && ok; if( !ok ) { ERR_PRINT("Could not add all required MgmtEventCallbacks to DBTManager: %s", toString().c_str()); @@ -381,6 +383,7 @@ BTAdapter::BTAdapter(const BTAdapter::ctor_cookie& cc, BTManagerRef mgmt_, Adapt hci_uses_ext_scan( false ), hci_uses_ext_conn( false ), hci_uses_ext_adv( false ), visibleAddressAndType( adapterInfo_.addressAndType ), visibleMACType( HCILEOwnAddressType::PUBLIC ), + privacyIRK(), dev_id( adapterInfo.dev_id ), btRole ( BTRole::Master ), hci( dev_id ), @@ -623,6 +626,42 @@ bool BTAdapter::setPowered(const bool power_on) noexcept { return power_on == isAdapterSettingBitSet(new_settings, AdapterSetting::POWERED); } +HCIStatusCode BTAdapter::setPrivacy(const bool enable) noexcept { + jau::uint128_t irk; + if( enable ) { + std::unique_ptr<std::random_device> rng_hw = std::make_unique<std::random_device>(); + for(int i=0; i<4; ++i) { + std::uint32_t v = (*rng_hw)(); + irk.data[4*i+0] = v & 0x000000ffu; + irk.data[4*i+1] = ( v & 0x0000ff00u ) >> 8; + irk.data[4*i+2] = ( v & 0x00ff0000u ) >> 16; + irk.data[4*i+3] = ( v & 0xff000000u ) >> 24; + } + } else { + irk.clear(); + } + AdapterSetting settings = adapterInfo.getCurrentSettingMask(); + HCIStatusCode res = mgmt->setPrivacy(dev_id, enable ? 0x01 : 0x00, irk, settings); + if( HCIStatusCode::SUCCESS == res ) { + if( enable ) { + // FIXME: Not working for LE set scan param etc .. + // TODO visibleAddressAndType = ??? + // visibleMACType = HCILEOwnAddressType::RESOLVABLE_OR_RANDOM; + visibleMACType = HCILEOwnAddressType::RESOLVABLE_OR_PUBLIC; + // visibleMACType = HCILEOwnAddressType::RANDOM; + } else { + visibleAddressAndType = adapterInfo.addressAndType; + visibleMACType = HCILEOwnAddressType::PUBLIC; + privacyIRK.address = adapterInfo.addressAndType.address; + privacyIRK.address_type = adapterInfo.addressAndType.type; + privacyIRK.irk.clear(); + } + } + const AdapterSetting new_settings = adapterInfo.setCurrentSettingMask(settings); + updateAdapterSettings(false /* off_thread */, new_settings, true /* sendEvent */, 0); + return res; +} + HCIStatusCode BTAdapter::setSecureConnections(const bool enable) noexcept { AdapterSetting settings = adapterInfo.getCurrentSettingMask(); if( isAdapterSettingBitSet(settings, AdapterSetting::POWERED) ) { @@ -2336,6 +2375,32 @@ void BTAdapter::mgmtEvNewLinkKeyMgmt(const MgmtEvent& e) noexcept { } } +void BTAdapter::mgmtEvNewIdentityResolvingKeyMgmt(const MgmtEvent& e) noexcept { + const MgmtEvtNewIdentityResolvingKey& event = *static_cast<const MgmtEvtNewIdentityResolvingKey *>(&e); + const EUI48& randomAddress = event.getRandomAddress(); + const MgmtIdentityResolvingKeyInfo& irk = event.getIdentityResolvingKey(); + if( adapterInfo.addressAndType.address == irk.address && adapterInfo.addressAndType.type == irk.address_type ) { + // setPrivacy ... + visibleAddressAndType.address = randomAddress; + visibleAddressAndType.type = BDAddressType::BDADDR_LE_RANDOM; + visibleMACType = HCILEOwnAddressType::RESOLVABLE_OR_RANDOM; + privacyIRK = irk; + WORDY_PRINT("BTAdapter::mgmt:NewIdentityResolvingKey(dev_id %d): Host Adapter: %s", + dev_id, event.toString().c_str()); + } else { + BTDeviceRef device = findConnectedDevice(randomAddress, BDAddressType::BDADDR_UNDEFINED); + if( nullptr != device ) { + // TODO: Notify our remove BDDevice instance about the resolved address! + // TODO: Support Random Address resolution! + WORDY_PRINT("BTAdapter::mgmt:NewIdentityResolvingKey(dev_id %d): Device found (Resolvable not yet supported): %s, %s", + dev_id, event.toString().c_str(), device->toString().c_str()); + } else { + WORDY_PRINT("BTAdapter::mgmt:NewIdentityResolvingKey(dev_id %d): Device not tracked: %s", + dev_id, event.toString().c_str()); + } + } +} + void BTAdapter::mgmtEvDeviceFoundHCI(const MgmtEvent& e) noexcept { // COND_PRINT(debug_event, "BTAdapter:hci:DeviceFound(dev_id %d): %s", dev_id, e.toString().c_str()); const MgmtEvtDeviceFound &deviceFoundEvent = *static_cast<const MgmtEvtDeviceFound *>(&e); diff --git a/src/direct_bt/BTManager.cpp b/src/direct_bt/BTManager.cpp index 84520ada..5a44228a 100644 --- a/src/direct_bt/BTManager.cpp +++ b/src/direct_bt/BTManager.cpp @@ -724,6 +724,14 @@ std::vector<MgmtDefaultParam> BTManager::readDefaultSysParam(const uint16_t dev_ return std::vector<MgmtDefaultParam>(); } +HCIStatusCode BTManager::setPrivacy(const uint16_t dev_id, const uint8_t privacy, const jau::uint128_t& irk, AdapterSetting& current_settings) noexcept { + MgmtSetPrivacyCmd req(dev_id, privacy, irk); + MgmtStatus res = handleCurrentSettingsReply(sendWithReply(req), current_settings); + DBG_PRINT("BTManager::setPrivacy[%d]: %s, result %s %s", dev_id, + req.toString().c_str(), to_string(res).c_str(), to_string(current_settings).c_str()); + return to_HCIStatusCode( res ); +} + HCIStatusCode BTManager::setDefaultConnParam(const uint16_t dev_id, const uint16_t conn_min_interval, const uint16_t conn_max_interval, const uint16_t conn_latency, const uint16_t supervision_timeout) noexcept { |