aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-10-25 11:35:23 +0200
committerSven Gothel <[email protected]>2023-10-25 11:35:23 +0200
commit2765a530e1a0bf77ec286c907ad613c0a4e1ca55 (patch)
treef9143771f9f4be17f218ee9b9f133527fb0bf975
parenta8fd6b54367108824512c172588f8ac16bd30393 (diff)
LE Resolvable Address: Handle identity- and resolvale-private-address (RPA), using RPA/IRK crypto matcher for HCI events (passing RPA)
HCIConnectionRef and BTDevice store both address pairs, naming the potential RPA as 'visibleAddressAndType'. BTAdapter's findDevice*() method seeks through all device's address first and if the potential RPA is not found queries each device whether it matches with its IRK (if existing). In case the latter is positive, the identity address has been found. Naturally, to have this work, the adapter (in server mode) needs to upload all keys to the host adapter to allow resolving as well as instantiating all devices per key-set. This concept has already been implemented, hence the IRK resolution change-set is not too dramatic. Trial unit tests passed.
-rw-r--r--api/direct_bt/BTAdapter.hpp18
-rw-r--r--api/direct_bt/BTAddress.hpp32
-rw-r--r--api/direct_bt/BTDevice.hpp35
-rw-r--r--api/direct_bt/HCIHandler.hpp27
-rw-r--r--api/direct_bt/SMPKeyBin.hpp16
-rw-r--r--java/jau/direct_bt/DBTAdapter.java5
-rw-r--r--java/jau/direct_bt/DBTDevice.java23
-rw-r--r--java/jni/direct_bt/DBTDevice.cxx27
-rw-r--r--java/org/direct_bt/BDAddressAndType.java39
-rw-r--r--java/org/direct_bt/BTDevice.java20
-rw-r--r--src/direct_bt/BTAdapter.cpp107
-rw-r--r--src/direct_bt/BTDevice.cpp60
-rw-r--r--src/direct_bt/HCIHandler.cpp14
-rw-r--r--src/direct_bt/SMPKeyBin.cpp16
14 files changed, 363 insertions, 76 deletions
diff --git a/api/direct_bt/BTAdapter.hpp b/api/direct_bt/BTAdapter.hpp
index 9fcfaa32..7570953d 100644
--- a/api/direct_bt/BTAdapter.hpp
+++ b/api/direct_bt/BTAdapter.hpp
@@ -349,7 +349,7 @@ namespace direct_bt {
*/
BDAddressAndType visibleAddressAndType;
HCILEOwnAddressType visibleMACType;
- MgmtIdentityResolvingKeyInfo privacyIRK;
+ MgmtIdentityResolvingKey privacyIRK;
public:
typedef jau::nsize_t size_type;
@@ -434,7 +434,7 @@ namespace direct_bt {
bool initialSetup() noexcept;
bool enableListening(const bool enable) noexcept;
- static BTDeviceRef findDevice(device_list_t & devices, const EUI48 & address, const BDAddressType addressType) noexcept;
+ static BTDeviceRef findDevice(HCIHandler& hci, device_list_t & devices, const EUI48 & address, const BDAddressType addressType) noexcept;
static BTDeviceRef findDevice(device_list_t & devices, BTDevice const & device) noexcept;
static BTDeviceRef findWeakDevice(weak_device_list_t & devices, const EUI48 & address, const BDAddressType addressType) noexcept;
static BTDeviceRef findWeakDevice(weak_device_list_t & devices, BTDevice const & device) noexcept;
@@ -474,6 +474,7 @@ namespace direct_bt {
uint16_t latency, uint16_t supervision_timeout) noexcept;
friend HCIStatusCode BTDevice::connectBREDR(const uint16_t pkt_type, const uint16_t clock_offset, const uint8_t role_switch) noexcept;
friend void BTDevice::processL2CAPSetup(BTDeviceRef sthis);
+ friend bool BTDevice::updateIdentityAddress(BDAddressAndType const & identityAddress, bool sendEvent) noexcept;
friend bool BTDevice::updatePairingState(const BTDeviceRef& sthis, const MgmtEvent& evt, const HCIStatusCode evtStatus, SMPPairingState claimed_state) noexcept;
friend void BTDevice::hciSMPMsgCallback(const BTDeviceRef& sthis, const SMPPDUMsg& msg, const HCIACLData::l2cap_frame& source) noexcept;
friend void BTDevice::processDeviceReady(BTDeviceRef sthis, const uint64_t timestamp);
@@ -525,14 +526,17 @@ namespace direct_bt {
void mgmtEvDeviceDiscoveringMgmt(const MgmtEvent& e) noexcept;
void mgmtEvLocalNameChangedMgmt(const MgmtEvent& e) noexcept;
void mgmtEvDeviceFoundHCI(const MgmtEvent& e) noexcept;
+
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 mgmtEvMgmtAnyMgmt(const MgmtEvent& e) noexcept;
void mgmtEvDeviceDiscoveringHCI(const MgmtEvent& e) noexcept;
void mgmtEvDeviceConnectedHCI(const MgmtEvent& e) noexcept;
+ void mgmtEvDeviceConnectedMgmt(const MgmtEvent& e) noexcept;
void mgmtEvConnectFailedHCI(const MgmtEvent& e) noexcept;
void mgmtEvHCILERemoteUserFeaturesHCI(const MgmtEvent& e) noexcept;
@@ -677,7 +681,7 @@ namespace direct_bt {
BTMode getBTMode() const noexcept { return adapterInfo.getCurrentBTMode(); }
/**
- * Returns the adapter's public BDAddressAndType.
+ * Returns the adapter's public BDAddressAndType, i.e. BDAddressType::BDADDR_LE_PUBLIC.
* <p>
* The adapter's address as initially reported by the system is always its public address, i.e. BDAddressType::BDADDR_LE_PUBLIC.
* </p>
@@ -687,15 +691,16 @@ namespace direct_bt {
BDAddressAndType const & getAddressAndType() const noexcept { return adapterInfo.addressAndType; }
/**
- * Returns the adapter's currently visible BDAddressAndType.
+ * Returns the adapter's currently visible BDAddressAndType, i.e. BDAddressType::BDADDR_LE_RANDOM or BDAddressType::BDADDR_LE_PUBLIC.
* <p>
* The adapter's address as initially reported by the system is always its public address, i.e. BDAddressType::BDADDR_LE_PUBLIC.
* </p>
* <p>
- * The adapter's visible BDAddressAndType might be set to BDAddressType::BDADDR_LE_RANDOM before scanning / discovery mode (TODO).
+ * The adapter's visible BDAddressAndType might be set to BDAddressType::BDADDR_LE_RANDOM before scanning / discovery mode via setPrivacy().
* </p>
- * @since 2.2.8
+ * @since 3.2.8
* @see #getAddressAndType()
+ * @see #setPrivacy()
*/
BDAddressAndType const & getVisibleAddressAndType() const noexcept { return visibleAddressAndType; }
@@ -753,6 +758,7 @@ namespace direct_bt {
* @param enable toggle to enable or disable (default)
* @return HCIStatusCode::SUCCESS or an error state on failure
* @since 3.2.0
+ * @see #getVisibleAddressAndType()
*/
HCIStatusCode setPrivacy(const bool enable) noexcept;
diff --git a/api/direct_bt/BTAddress.hpp b/api/direct_bt/BTAddress.hpp
index 493f8d6d..1e0a2466 100644
--- a/api/direct_bt/BTAddress.hpp
+++ b/api/direct_bt/BTAddress.hpp
@@ -218,6 +218,38 @@ namespace direct_bt {
}
/**
+ * Returns true if this address and type refers to a static public LE identity address,
+ * which does not require address resolution via an Identity Resolving Key (IRK).<br>
+ * Either ::BDAddressType::BDADDR_LE_PUBLIC or ::BDAddressType::BDADDR_LE_RANDOM of sub-type ::BLERandomAddressType::STATIC_PUBLIC.
+ */
+ constexpr bool isIdentityLEAddress() const noexcept {
+ if( BDAddressType::BDADDR_LE_RANDOM == type ) {
+ return BLERandomAddressType::STATIC_PUBLIC == getBLERandomAddressType();
+ } else {
+ return BDAddressType::BDADDR_LE_PUBLIC == type;
+ }
+ }
+
+ /**
+ * Returns true if this address and type refers to a public static identity address,
+ * which does not require address resolution via an Identity Resolving Key (IRK).<br>
+ * This includes ::BDAddressType::BDADDR_LE_RANDOM of sub-type ::BLERandomAddressType::STATIC_PUBLIC
+ * <p>
+ * Returns false if this address is of type ::BDAddressType::BDADDR_LE_RANDOM,
+ * excluding sub-type ::BLERandomAddressType::STATIC_PUBLIC
+ * and not of type ::BDAddressType::BDADDR_LE_PUBLIC or ::BDAddressType::BDADDR_BREDR.
+ * </p>
+ */
+ constexpr bool isIdentityAddress() const noexcept {
+ if( BDAddressType::BDADDR_LE_RANDOM == type ) {
+ return BLERandomAddressType::STATIC_PUBLIC == getBLERandomAddressType();
+ } else {
+ return BDAddressType::BDADDR_LE_PUBLIC == type ||
+ BDAddressType::BDADDR_BREDR == type;
+ }
+ }
+
+ /**
* Returns true if the BDAddressType is a BREDR address type.
*/
constexpr bool isBREDRAddress() const noexcept { return BDAddressType::BDADDR_BREDR == type; }
diff --git a/api/direct_bt/BTDevice.hpp b/api/direct_bt/BTDevice.hpp
index 6b0e814f..1437370f 100644
--- a/api/direct_bt/BTDevice.hpp
+++ b/api/direct_bt/BTDevice.hpp
@@ -168,6 +168,8 @@ namespace direct_bt {
void clearData() noexcept;
+ bool updateIdentityAddress(BDAddressAndType const & identityAddress, bool sendEvent) noexcept;
+ bool updateVisibleAddress(BDAddressAndType const & randomPrivateAddress) noexcept;
EIRDataType update(EInfoReport const & data) noexcept;
EIRDataType update(GattGenericAccessSvc const &data, const uint64_t timestamp) noexcept;
@@ -255,8 +257,10 @@ namespace direct_bt {
typedef jau::snsize_t ssize_type;
const uint64_t ts_creation;
- /** Device's unique mac address and type tuple. */
- const BDAddressAndType addressAndType; // FIXME: Mutable for resolvable -> identity during pairing?
+ /** Either the remote devices' initially reported (resolvable) random address or its (static) public identity address. */
+ BDAddressAndType visibleAddressAndType;
+ /** Device's unique mac address and type tuple, might be its initially reported (resolvable) random address until pairing. */
+ BDAddressAndType addressAndType;
/** Private ctor for private BTDevice::make_shared() intended for friends. */
BTDevice(const BTDevice::ctor_cookie& cc, BTAdapter & adapter, EInfoReport const & r);
@@ -325,11 +329,27 @@ namespace direct_bt {
uint64_t getLastUpdateAge(const uint64_t ts_now) const noexcept { return ts_now - ts_last_update; }
/**
- * Returns the unique device EUI48 address and BDAddressType type.
- * @since 2.2.0
+ * Returns the devices' unique EUI48 address and type tuple, might be its initially reported (resolvable) random address until pairing,
+ * i.e. BDAddressType::BDADDR_LE_RANDOM instead of BDAddressType::BDADDR_LE_PUBLIC.
+ * <p>
+ * After pairing or if the remote device uses a (static) public address,
+ * it is considered unique and BDAddressType::BDADDR_LE_PUBLIC.
+ * </p>
+ * @since 3.2.0
*/
constexpr BDAddressAndType const & getAddressAndType() const noexcept { return addressAndType; }
+ /**
+ * Returns the devices' visible BDAddressAndType, i.e. BDAddressType::BDADDR_LE_RANDOM or BDAddressType::BDADDR_LE_PUBLIC
+ * <p>
+ * The devices' address as initially reported by the system might be a (resolvable) random address,
+ * i.e. BDAddressType::BDADDR_LE_RANDOM instead of BDAddressType::BDADDR_LE_PUBLIC.
+ * </p>
+ * @since 3.2.8
+ * @see #getAddressAndType()
+ */
+ BDAddressAndType const & getVisibleAddressAndType() const noexcept { return visibleAddressAndType; }
+
/** Return RSSI of device as recognized at discovery and connect. */
int8_t getRSSI() const noexcept { return rssi; }
@@ -1241,8 +1261,11 @@ namespace direct_bt {
size_type removeAllCharListener() noexcept;
};
- inline bool operator==(const BTDevice& lhs, const BTDevice& rhs) noexcept
- { return lhs.getAddressAndType() == rhs.getAddressAndType(); }
+ inline bool operator==(const BTDevice& lhs, const BTDevice& rhs) noexcept {
+ return lhs.getAddressAndType() == rhs.getAddressAndType() ||
+ lhs.getVisibleAddressAndType() == rhs.getVisibleAddressAndType() // FIXME: Evaluate if OK w/o collisions
+ ;
+ }
inline bool operator!=(const BTDevice& lhs, const BTDevice& rhs) noexcept
{ return !(lhs == rhs); }
diff --git a/api/direct_bt/HCIHandler.hpp b/api/direct_bt/HCIHandler.hpp
index 3ece4bca..8f329d52 100644
--- a/api/direct_bt/HCIHandler.hpp
+++ b/api/direct_bt/HCIHandler.hpp
@@ -189,31 +189,35 @@ namespace direct_bt {
private:
class HCIConnection {
private:
- BDAddressAndType addressAndType; // immutable
+ BDAddressAndType visibleAddressAndType; // immutable
+ BDAddressAndType addressAndType; // mutable
uint16_t handle; // mutable
public:
- HCIConnection(BDAddressAndType addressAndType_, const uint16_t handle_)
- : addressAndType(std::move(addressAndType_)), handle(handle_) {}
+ HCIConnection(const BDAddressAndType& addressAndType_, const uint16_t handle_)
+ : visibleAddressAndType(addressAndType_), addressAndType(addressAndType_), handle(handle_) {}
HCIConnection(const HCIConnection &o) = default;
HCIConnection(HCIConnection &&o) = default;
HCIConnection& operator=(const HCIConnection &o) = default;
HCIConnection& operator=(HCIConnection &&o) = default;
+ const BDAddressAndType & getVisibleAddressAndType() const { return visibleAddressAndType; }
const BDAddressAndType & getAddressAndType() const { return addressAndType; }
+ void setResolvAddrAndType(const BDAddressAndType& val) { addressAndType = val; }
+
uint16_t getHandle() const { return handle; }
void setHandle(uint16_t newHandle) { handle = newHandle; }
bool equals(const BDAddressAndType & other) const
- { return addressAndType == other; }
+ { return addressAndType == other || visibleAddressAndType == other; }
bool operator==(const HCIConnection& rhs) const {
if( this == &rhs ) {
return true;
}
- return addressAndType == rhs.addressAndType;
+ return addressAndType == rhs.addressAndType || visibleAddressAndType == rhs.visibleAddressAndType;
}
bool operator!=(const HCIConnection& rhs) const
@@ -224,8 +228,9 @@ namespace direct_bt {
}
std::string toString() const {
+ std::string resaddr_s = visibleAddressAndType != addressAndType ? ", visible "+visibleAddressAndType.toString() : "";
return "HCIConnection[handle "+jau::to_hexstring(handle)+
- ", address "+addressAndType.toString()+"]";
+ ", address "+addressAndType.toString()+resaddr_s+"]";
}
};
public:
@@ -286,6 +291,16 @@ namespace direct_bt {
/** Exclusive [le] connection command (status + pending completed) one at a time */
std::mutex mtx_connect_cmd;
+ HCIConnectionRef setResolvHCIConnectionAddr(jau::darray<HCIConnectionRef> &list,
+ const BDAddressAndType& visibleAddressAndType, const BDAddressAndType& addressAndType) noexcept;
+
+ public:
+ void setResolvHCIConnectionAddr(const BDAddressAndType& visibleAddressAndType, const BDAddressAndType& addressAndType) noexcept {
+ setResolvHCIConnectionAddr(connectionList, visibleAddressAndType, addressAndType);
+ setResolvHCIConnectionAddr(disconnectCmdList, visibleAddressAndType, addressAndType);
+ }
+
+ private:
/**
* Returns a newly added HCIConnectionRef tracker connection with given parameters, if not existing yet.
* <p>
diff --git a/api/direct_bt/SMPKeyBin.hpp b/api/direct_bt/SMPKeyBin.hpp
index acf7d476..48ad8a47 100644
--- a/api/direct_bt/SMPKeyBin.hpp
+++ b/api/direct_bt/SMPKeyBin.hpp
@@ -290,10 +290,10 @@ class SMPKeyBin {
constexpr BTSecurityLevel getSecLevel() const noexcept { return sec_level; }
constexpr SMPIOCapability getIOCap() const noexcept { return io_cap; }
- constexpr bool hasLTKInit() const noexcept { return ( SMPKeyType::ENC_KEY & keys_init ) != SMPKeyType::NONE; }
- constexpr bool hasIRKInit() const noexcept { return ( SMPKeyType::ID_KEY & keys_init ) != SMPKeyType::NONE; }
- constexpr bool hasCSRKInit() const noexcept { return ( SMPKeyType::SIGN_KEY & keys_init ) != SMPKeyType::NONE; }
- constexpr bool hasLKInit() const noexcept { return ( SMPKeyType::LINK_KEY & keys_init ) != SMPKeyType::NONE; }
+ constexpr bool hasLTKInit() const noexcept { return is_set(keys_init, SMPKeyType::ENC_KEY); }
+ constexpr bool hasIRKInit() const noexcept { return is_set(keys_init, SMPKeyType::ID_KEY); }
+ constexpr bool hasCSRKInit() const noexcept { return is_set(keys_init, SMPKeyType::SIGN_KEY); }
+ constexpr bool hasLKInit() const noexcept { return is_set(keys_init, SMPKeyType::LINK_KEY); }
constexpr const SMPLongTermKey& getLTKInit() const noexcept { return ltk_init; }
constexpr const SMPIdentityResolvingKey& getIRKInit() const noexcept { return irk_init; }
constexpr const SMPSignatureResolvingKey& getCSRKInit() const noexcept { return csrk_init; }
@@ -319,10 +319,10 @@ class SMPKeyBin {
size = calcSize();
}
- constexpr bool hasLTKResp() const noexcept { return ( SMPKeyType::ENC_KEY & keys_resp ) != SMPKeyType::NONE; }
- constexpr bool hasIRKResp() const noexcept { return ( SMPKeyType::ID_KEY & keys_resp ) != SMPKeyType::NONE; }
- constexpr bool hasCSRKResp() const noexcept { return ( SMPKeyType::SIGN_KEY & keys_resp ) != SMPKeyType::NONE; }
- constexpr bool hasLKResp() const noexcept { return ( SMPKeyType::LINK_KEY & keys_resp ) != SMPKeyType::NONE; }
+ constexpr bool hasLTKResp() const noexcept { return is_set(keys_resp, SMPKeyType::ENC_KEY); }
+ constexpr bool hasIRKResp() const noexcept { return is_set(keys_resp, SMPKeyType::ID_KEY); }
+ constexpr bool hasCSRKResp() const noexcept { return is_set(keys_resp, SMPKeyType::SIGN_KEY); }
+ constexpr bool hasLKResp() const noexcept { return is_set(keys_resp, SMPKeyType::LINK_KEY); }
constexpr const SMPLongTermKey& getLTKResp() const noexcept { return ltk_resp; }
constexpr const SMPIdentityResolvingKey& getIRKResp() const noexcept { return irk_resp; }
constexpr const SMPSignatureResolvingKey& getCSRKResp() const noexcept { return csrk_resp; }
diff --git a/java/jau/direct_bt/DBTAdapter.java b/java/jau/direct_bt/DBTAdapter.java
index 78f40d4f..55b1af4e 100644
--- a/java/jau/direct_bt/DBTAdapter.java
+++ b/java/jau/direct_bt/DBTAdapter.java
@@ -99,7 +99,7 @@ public class DBTAdapter extends DBTObject implements BTAdapter
{
super(nativeInstance, compHash(java.util.Arrays.hashCode(byteAddress), 31+byteAddressType));
this.dev_id = dev_id;
- this.addressAndType = new BDAddressAndType(new EUI48(byteAddress, ByteOrder.nativeOrder()), BDAddressType.get(byteAddressType));
+ this.addressAndType = new BDAddressAndType(byteAddress, 0, byteAddressType);
this.name_cached = name;
this.visibleAddressAndType = addressAndType;
addStatusListener(this.statusListener);
@@ -607,6 +607,9 @@ public class DBTAdapter extends DBTObject implements BTAdapter
@Override
public void deviceUpdated(final BTDevice device, final EIRDataTypeSet updateMask, final long timestamp) {
+ if( updateMask.isSet( EIRDataTypeSet.DataType.BDADDR ) ) {
+ ((DBTDevice)device).updateAddress();
+ }
final boolean rssiUpdated = updateMask.isSet( EIRDataTypeSet.DataType.RSSI );
final boolean mdUpdated = updateMask.isSet( EIRDataTypeSet.DataType.MANUF_DATA );
if( DEBUG && !rssiUpdated && !mdUpdated) {
diff --git a/java/jau/direct_bt/DBTDevice.java b/java/jau/direct_bt/DBTDevice.java
index 5fb0ea9a..a73282a2 100644
--- a/java/jau/direct_bt/DBTDevice.java
+++ b/java/jau/direct_bt/DBTDevice.java
@@ -29,6 +29,7 @@ import java.lang.ref.WeakReference;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import org.direct_bt.AdapterStatusListener;
@@ -63,7 +64,8 @@ public class DBTDevice extends DBTObject implements BTDevice
/** Device's adapter weak back-reference */
private final WeakReference<DBTAdapter> wbr_adapter;
- private final BDAddressAndType addressAndType;
+ private BDAddressAndType addressAndType;
+ private final BDAddressAndType visibleAddressAndType;
private final long ts_creation;
volatile long ts_last_discovery;
volatile long ts_last_update;
@@ -85,7 +87,8 @@ public class DBTDevice extends DBTObject implements BTDevice
{
super(nativeInstance, compHash(java.util.Arrays.hashCode(byteAddress), 31+byteAddressType));
this.wbr_adapter = new WeakReference<DBTAdapter>(adptr);
- this.addressAndType = new BDAddressAndType(new EUI48(byteAddress, ByteOrder.nativeOrder()), BDAddressType.get(byteAddressType));
+ this.visibleAddressAndType = new BDAddressAndType(byteAddress, 0, byteAddressType);
+ this.addressAndType = new BDAddressAndType(this.visibleAddressAndType);
if( BDAddressType.BDADDR_UNDEFINED == addressAndType.type ) {
throw new IllegalArgumentException("Unsupported given native addresstype "+byteAddressType);
}
@@ -98,6 +101,16 @@ public class DBTDevice extends DBTObject implements BTDevice
// FIXME enableTrustedNotificationsImpl(trustedNotificationsCB);
}
+ /* pp */ void updateAddress() {
+ final byte byteAddress[/*6*/] = getAddressImpl();
+ final byte byteAddressType = getAddressTypeImpl();
+ if( null != byteAddress && 0 != byteAddressType ) {
+ addressAndType = new BDAddressAndType(byteAddress, 0, byteAddressType);
+ }
+ }
+ private native byte[] getAddressImpl();
+ private native byte getAddressTypeImpl();
+
@Override
public void close() {
if( !isValid() ) {
@@ -143,13 +156,17 @@ public class DBTDevice extends DBTObject implements BTDevice
return false;
}
final DBTDevice other = (DBTDevice)obj;
- return addressAndType.equals(other.addressAndType);
+ return addressAndType.equals(other.addressAndType) ||
+ visibleAddressAndType.equals(other.visibleAddressAndType); // FIXME: Evaluate if OK w/o collisions
}
@Override
public BDAddressAndType getAddressAndType() { return addressAndType; }
@Override
+ public BDAddressAndType getVisibleAddressAndType() { return visibleAddressAndType; }
+
+ @Override
public String getName() {
if( !isValid() ) {
return name_cached;
diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx
index 7f667dba..f7c54a68 100644
--- a/java/jni/direct_bt/DBTDevice.cxx
+++ b/java/jni/direct_bt/DBTDevice.cxx
@@ -215,6 +215,33 @@ jstring Java_jau_direct_1bt_DBTDevice_toStringImpl(JNIEnv *env, jobject obj) {
return nullptr;
}
+jbyteArray Java_jau_direct_1bt_DBTDevice_getAddressImpl(JNIEnv *env, jobject obj) {
+ try {
+ shared_ptr_ref<BTDevice> device(env, obj); // hold until done
+ JavaAnonRef device_java = device->getJavaObject(); // hold until done!
+ JavaGlobalObj::check(device_java, E_FILE_LINE);
+ const EUI48 & addr = device->getAddressAndType().address;
+ jbyteArray jaddr = env->NewByteArray(sizeof(addr));
+ env->SetByteArrayRegion(jaddr, 0, sizeof(addr), (const jbyte*)(addr.b));
+ return jaddr;
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return nullptr;
+}
+
+jbyte Java_jau_direct_1bt_DBTDevice_getAddressTypeImpl(JNIEnv *env, jobject obj) {
+ try {
+ shared_ptr_ref<BTDevice> device(env, obj); // hold until done
+ JavaAnonRef device_java = device->getJavaObject(); // hold until done!
+ JavaGlobalObj::check(device_java, E_FILE_LINE);
+ return static_cast<jbyte>( number( device->getAddressAndType().type ) );
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+ return 0;
+}
+
/*
* Class: jau_direct_bt_DBTDevice
* Method: addCharListenerImpl
diff --git a/java/org/direct_bt/BDAddressAndType.java b/java/org/direct_bt/BDAddressAndType.java
index 2ed607f4..017bd1fd 100644
--- a/java/org/direct_bt/BDAddressAndType.java
+++ b/java/org/direct_bt/BDAddressAndType.java
@@ -25,6 +25,8 @@
package org.direct_bt;
+import java.nio.ByteOrder;
+
import org.jau.net.EUI48;
/**
@@ -50,6 +52,11 @@ public class BDAddressAndType {
private volatile int hash; // default 0, cache
+ public BDAddressAndType(final byte[/*6*/] stream, final int pos, final byte byteAddressType) {
+ this.address = new EUI48(stream, pos, ByteOrder.nativeOrder());
+ this.type = BDAddressType.get(byteAddressType);
+ }
+
public BDAddressAndType(final EUI48 address, final BDAddressType type) {
this.address = address;
this.type = type;
@@ -73,6 +80,38 @@ public class BDAddressAndType {
}
/**
+ * Returns true if this address and type refers to a static public LE identity address,
+ * which does not require address resolution via an Identity Resolving Key (IRK).<br>
+ * Either {@link BDAddressType#BDADDR_LE_PUBLIC} or {@link BDAddressType#BDADDR_LE_RANDOM} of sub-type {@link BLERandomAddressType#STATIC_PUBLIC}.
+ */
+ public boolean isIdentityLEAddress() {
+ if( BDAddressType.BDADDR_LE_RANDOM == type ) {
+ return BLERandomAddressType.STATIC_PUBLIC == getBLERandomAddressType();
+ } else {
+ return BDAddressType.BDADDR_LE_PUBLIC == type;
+ }
+ }
+
+ /**
+ * Returns true if this address and type refers to a static public identity address,
+ * which does not require address resolution via an Identity Resolving Key (IRK).<br>
+ * This includes {@link BDAddressType#BDADDR_LE_RANDOM} of sub-type {@link BLERandomAddressType#STATIC_PUBLIC}.
+ * <p>
+ * Returns false if this address is of type {@link BDAddressType#BDADDR_LE_RANDOM},
+ * excluding sub-type {@link BLERandomAddressType#STATIC_PUBLIC}
+ * and not of type {@link BDAddressType#BDADDR_LE_PUBLIC} or {@link BDAddressType#BDADDR_BREDR}.
+ * </p>
+ */
+ public boolean isIdentityAddress() {
+ if( BDAddressType.BDADDR_LE_RANDOM == type ) {
+ return BLERandomAddressType.STATIC_PUBLIC == getBLERandomAddressType();
+ } else {
+ return BDAddressType.BDADDR_LE_PUBLIC == type ||
+ BDAddressType.BDADDR_BREDR == type;
+ }
+ }
+
+ /**
* Returns true if the given {@link BDAddressType} is a BREDR address type.
*/
public boolean isBREDRAddress() { return BDAddressType.BDADDR_BREDR == type; }
diff --git a/java/org/direct_bt/BTDevice.java b/java/org/direct_bt/BTDevice.java
index cc6b0f33..f3b18f94 100644
--- a/java/org/direct_bt/BTDevice.java
+++ b/java/org/direct_bt/BTDevice.java
@@ -794,12 +794,28 @@ public interface BTDevice extends BTObject
boolean equals(final Object obj);
/**
- * Returns the unique device {@link EUI48} address and {@link BDAddressType} type.
- * @since 2.2.0
+ * Returns the devices' unique {@link EUI48} address and {@link BDAddressType} type tuple, might be its initially reported (resolvable) random address until pairing,
+ * i.e. {@link BDAddressType#BDADDR_LE_RANDOM} instead of {@link BDAddressType#BDADDR_LE_PUBLIC}.
+ * <p>
+ * After pairing or if the remote device uses a (static) public address,
+ * it is considered unique and {@link BDAddressType#BDADDR_LE_PUBLIC}.
+ * </p>
+ * @since 3.2.0
*/
BDAddressAndType getAddressAndType();
/**
+ * Returns the devices' visible BDAddressAndType, i.e. {@link BDAddressType#BDADDR_LE_RANDOM} or {@link BDAddressType#BDADDR_LE_PUBLIC}.
+ * <p>
+ * The devices' address as initially reported by the system might be a (resolvable) random address,
+ * i.e. {@link BDAddressType#BDADDR_LE_RANDOM} instead of {@link BDAddressType#BDADDR_LE_PUBLIC}.
+ * </p>
+ * @since 3.2.8
+ * @see #getAddressAndType()
+ */
+ BDAddressAndType getVisibleAddressAndType();
+
+ /**
* Returns the remote device name.
*
* The name has been set by the advertised {@link EInfoReport} if available,
diff --git a/src/direct_bt/BTAdapter.cpp b/src/direct_bt/BTAdapter.cpp
index f22b3ff0..61302e79 100644
--- a/src/direct_bt/BTAdapter.cpp
+++ b/src/direct_bt/BTAdapter.cpp
@@ -66,17 +66,39 @@ std::string direct_bt::to_string(const DiscoveryPolicy v) noexcept {
return "Unknown DiscoveryPolicy "+jau::to_hexstring(number(v));
}
-BTDeviceRef BTAdapter::findDevice(device_list_t & devices, const EUI48 & address, const BDAddressType addressType) noexcept {
+BTDeviceRef BTAdapter::findDevice(HCIHandler& hci, device_list_t & devices, const EUI48 & address, const BDAddressType addressType) noexcept {
+ BDAddressAndType rpa(address, addressType);
const jau::nsize_t size = devices.size();
for (jau::nsize_t i = 0; i < size; ++i) {
BTDeviceRef & e = devices[i];
- if ( nullptr != e && address == e->getAddressAndType().address &&
- ( addressType == e->getAddressAndType().type || addressType == BDAddressType::BDADDR_UNDEFINED )
+ if ( nullptr != e &&
+ (
+ ( address == e->getAddressAndType().address &&
+ ( addressType == e->getAddressAndType().type || addressType == BDAddressType::BDADDR_UNDEFINED )
+ ) ||
+ ( address == e->getVisibleAddressAndType().address &&
+ ( addressType == e->getVisibleAddressAndType().type || addressType == BDAddressType::BDADDR_UNDEFINED )
+ )
+ )
)
{
+ if( !rpa.isIdentityAddress() ) {
+ e->updateVisibleAddress(rpa);
+ hci.setResolvHCIConnectionAddr(rpa, e->getAddressAndType());
+ }
return e;
}
}
+ if( !rpa.isIdentityAddress() ) {
+ for (jau::nsize_t i = 0; i < size; ++i) {
+ BTDeviceRef & e = devices[i];
+ if ( nullptr != e && e->matches_irk(rpa) ) {
+ e->updateVisibleAddress(rpa);
+ hci.setResolvHCIConnectionAddr(rpa, e->getAddressAndType());
+ return e;
+ }
+ }
+ }
return nullptr;
}
@@ -98,8 +120,12 @@ BTDeviceRef BTAdapter::findWeakDevice(weak_device_list_t & devices, const EUI48
BTDeviceRef e = w.lock();
if( nullptr == e ) {
devices.erase(it); // erase and move it to next element
- } else if ( address == e->getAddressAndType().address &&
- ( addressType == e->getAddressAndType().type || addressType == BDAddressType::BDADDR_UNDEFINED )
+ } else if ( ( address == e->getAddressAndType().address &&
+ ( addressType == e->getAddressAndType().type || addressType == BDAddressType::BDADDR_UNDEFINED )
+ ) ||
+ ( address == e->getVisibleAddressAndType().address &&
+ ( addressType == e->getVisibleAddressAndType().type || addressType == BDAddressType::BDADDR_UNDEFINED )
+ )
)
{
return e;
@@ -230,7 +256,7 @@ BTAdapter::size_type BTAdapter::disconnectAllDevices(const HCIStatusCode reason)
BTDeviceRef BTAdapter::findConnectedDevice (const EUI48 & address, const BDAddressType & addressType) noexcept {
const std::lock_guard<std::mutex> lock(mtx_connectedDevices); // RAII-style acquire and relinquish via destructor
- return findDevice(connectedDevices, address, addressType);
+ return findDevice(hci, connectedDevices, address, addressType);
}
jau::nsize_t BTAdapter::getConnectedDeviceCount() const noexcept {
@@ -255,9 +281,13 @@ bool BTAdapter::updateDataFromHCI() noexcept {
hci_uses_ext_conn = hci.use_ext_conn();
hci_uses_ext_adv = hci.use_ext_adv();
+ status = hci.le_set_addr_resolv_enable(true);
+ if( HCIStatusCode::SUCCESS != status ) {
+ jau::INFO_PRINT("Adapter[%d]: ENABLE RESOLV LIST: %s", dev_id, to_string(status).c_str());
+ }
status = hci.le_clear_resolv_list();
if( HCIStatusCode::SUCCESS != status ) {
- jau::INFO_PRINT("Adapter[%d]: CLEAR RESOLV LIST failed %s", dev_id, to_string(status).c_str());
+ jau::INFO_PRINT("Adapter[%d]: CLEAR RESOLV LIST: %s", dev_id, to_string(status).c_str());
}
WORDY_PRINT("BTAdapter::updateDataFromHCI: Adapter[%d]: POWERED, %s - %s, hci_ext[scan %d, conn %d], features: %s",
@@ -340,6 +370,11 @@ bool BTAdapter::enableListening(const bool enable) noexcept {
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( debug_event || jau::environment::get().debug ) {
+ ok = mgmt->addMgmtEventCallback(dev_id, MgmtEvent::Opcode::DEVICE_CONNECTED, jau::bind_member(this, &BTAdapter::mgmtEvDeviceConnectedMgmt)) && ok;
+ ok = mgmt->addMgmtEventCallback(dev_id, MgmtEvent::Opcode::DEVICE_DISCONNECTED, jau::bind_member(this, &BTAdapter::mgmtEvMgmtAnyMgmt)) && ok;
+ }
+
if( !ok ) {
ERR_PRINT("Could not add all required MgmtEventCallbacks to DBTManager: %s", toString().c_str());
return false;
@@ -509,8 +544,8 @@ void BTAdapter::poweredOff(bool active, const std::string& msg) noexcept {
stopDiscoveryImpl(true /* forceDiscoveringEvent */, false /* temporary */);
}
- // Removes all device references from the lists: connectedDevices, discoveredDevices, sharedDevices
- disconnectAllDevices();
+ // Removes all device references from the lists: connectedDevices, discoveredDevices
+ disconnectAllDevices(HCIStatusCode::NOT_POWERED);
removeDiscoveredDevices();
// ensure all hci states are reset.
@@ -551,9 +586,10 @@ void BTAdapter::printDeviceList(const std::string& prefix, const BTAdapter::devi
} else if( (*it)->isValidInstance() /** TODO: See above */ ) {
jau::PLAIN_PRINT(true, " - %d / %zu: invalid", (idx+1), sz);
} else {
- jau::PLAIN_PRINT(true, " - %d / %zu: %s, name '%s'", (idx+1), sz,
+ jau::PLAIN_PRINT(true, " - %d / %zu: %s, name '%s', visible %s", (idx+1), sz,
(*it)->getAddressAndType().toString().c_str(),
- (*it)->getName().c_str() );
+ (*it)->getName().c_str(),
+ (*it)->getVisibleAddressAndType().toString().c_str());
}
PRAGMA_DISABLE_WARNING_POP
}
@@ -570,9 +606,10 @@ void BTAdapter::printWeakDeviceList(const std::string& prefix, BTAdapter::weak_d
} else if( !e->isValidInstance() ) {
jau::PLAIN_PRINT(true, " - %d / %zu: invalid", (idx+1), sz);
} else {
- jau::PLAIN_PRINT(true, " - %d / %zu: %s, name '%s'", (idx+1), sz,
+ jau::PLAIN_PRINT(true, " - %d / %zu: %s, name '%s', visible %s", (idx+1), sz,
e->getAddressAndType().toString().c_str(),
- e->getName().c_str() );
+ e->getName().c_str(),
+ e->getVisibleAddressAndType().toString().c_str());
}
}
}
@@ -1327,7 +1364,7 @@ exit:
BTDeviceRef BTAdapter::findDiscoveredDevice (const EUI48 & address, const BDAddressType addressType) noexcept {
const std::lock_guard<std::mutex> lock(mtx_discoveredDevices); // RAII-style acquire and relinquish via destructor
- return findDevice(discoveredDevices, address, addressType);
+ return findDevice(hci, discoveredDevices, address, addressType);
}
bool BTAdapter::addDiscoveredDevice(BTDeviceRef const &device) noexcept {
@@ -1417,7 +1454,7 @@ void BTAdapter::removeSharedDevice(const BTDevice & device) noexcept {
BTDeviceRef BTAdapter::findSharedDevice (const EUI48 & address, const BDAddressType addressType) noexcept {
const std::lock_guard<std::mutex> lock(mtx_sharedDevices); // RAII-style acquire and relinquish via destructor
- return findDevice(sharedDevices, address, addressType);
+ return findDevice(hci, sharedDevices, address, addressType);
}
// *************************************************
@@ -1691,6 +1728,10 @@ void BTAdapter::mgmtEvHCIAnyHCI(const MgmtEvent& e) noexcept {
DBG_PRINT("BTAdapter:hci::Any: %s", e.toString().c_str());
(void)e;
}
+void BTAdapter::mgmtEvMgmtAnyMgmt(const MgmtEvent& e) noexcept {
+ DBG_PRINT("BTAdapter:mgmt:Any: %s", e.toString().c_str());
+ (void)e;
+}
void BTAdapter::mgmtEvDeviceDiscoveringHCI(const MgmtEvent& e) noexcept {
const MgmtEvtDiscovering &event = *static_cast<const MgmtEvtDiscovering *>(&e);
@@ -1813,7 +1854,7 @@ void BTAdapter::updateAdapterSettings(const bool off_thread, const AdapterSettin
if( justPoweredOff ) {
// Adapter has been powered off, close connections and cleanup off-thread.
if( off_thread ) {
- std::thread bg(&BTAdapter::poweredOff, this, false, "powered_off.0"); // @suppress("Invalid arguments")
+ std::thread bg(&BTAdapter::poweredOff, this, false, "adapter_settings.0"); // @suppress("Invalid arguments")
bg.detach();
} else {
poweredOff(false, "powered_off.1");
@@ -1861,8 +1902,8 @@ void BTAdapter::l2capServerEnd(jau::service_runner& sr) noexcept {
void BTAdapter::l2capServerWork(jau::service_runner& sr) noexcept {
(void)sr;
std::unique_ptr<L2CAPClient> l2cap_att_ = l2cap_att_srv.accept();
- if( BTRole::Slave == getRole() && nullptr != l2cap_att_ ) {
- DBG_PRINT("L2CAP-ACCEPT: BTAdapter::l2capServer connected.1: %s", l2cap_att_->toString().c_str());
+ if( BTRole::Slave == getRole() && nullptr != l2cap_att_ && l2cap_att_->getRemoteAddressAndType().isIdentityLEAddress() ) {
+ DBG_PRINT("L2CAP-ACCEPT: BTAdapter::l2capServer connected.1: (public) %s", l2cap_att_->toString().c_str());
std::unique_lock<std::mutex> lock(mtx_l2cap_att); // RAII-style acquire and relinquish via destructor
l2cap_att = std::move( l2cap_att_ );
@@ -1870,7 +1911,7 @@ void BTAdapter::l2capServerWork(jau::service_runner& sr) noexcept {
cv_l2cap_att.notify_all(); // notify waiting getter
} else if( nullptr != l2cap_att_ ) {
- DBG_PRINT("L2CAP-ACCEPT: BTAdapter::l2capServer connected.2: %s", l2cap_att_->toString().c_str());
+ DBG_PRINT("L2CAP-ACCEPT: BTAdapter::l2capServer connected.2: (ignored) %s", l2cap_att_->toString().c_str());
} else {
DBG_PRINT("L2CAP-ACCEPT: BTAdapter::l2capServer connected.0: nullptr");
}
@@ -1960,6 +2001,8 @@ void BTAdapter::mgmtEvDeviceConnectedHCI(const MgmtEvent& e) noexcept {
ad_report.setAddress( event.getAddress() );
ad_report.read_data(event.getData(), event.getDataSize());
}
+ DBG_PRINT("BTAdapter::mgmtEvDeviceConnectedHCI(dev_id %d): Event %s, AD EIR %s",
+ dev_id, e.toString().c_str(), ad_report.toString(true).c_str());
int new_connect = 0;
bool device_discovered = true;
@@ -2080,6 +2123,19 @@ void BTAdapter::mgmtEvDeviceConnectedHCI(const MgmtEvent& e) noexcept {
device->notifyLEFeatures(device, LE_Features::LE_Encryption);
}
}
+void BTAdapter::mgmtEvDeviceConnectedMgmt(const MgmtEvent& e) noexcept {
+ const MgmtEvtDeviceConnected &event = *static_cast<const MgmtEvtDeviceConnected *>(&e);
+ EInfoReport ad_report;
+ {
+ ad_report.setSource(EInfoReport::Source::EIR, false);
+ ad_report.setTimestamp(event.getTimestamp());
+ ad_report.setAddressType(event.getAddressType());
+ ad_report.setAddress( event.getAddress() );
+ ad_report.read_data(event.getData(), event.getDataSize());
+ }
+ DBG_PRINT("BTAdapter::mgmtEvDeviceConnectedMgmt(dev_id %d): Event %s, AD EIR %s",
+ dev_id, e.toString().c_str(), ad_report.toString(true).c_str());
+}
void BTAdapter::mgmtEvConnectFailedHCI(const MgmtEvent& e) noexcept {
const MgmtEvtDeviceConnectFailed &event = *static_cast<const MgmtEvtDeviceConnectFailed *>(&e);
@@ -2347,7 +2403,7 @@ void BTAdapter::mgmtEvPairDeviceCompleteMgmt(const MgmtEvent& e) noexcept {
void BTAdapter::mgmtEvNewLongTermKeyMgmt(const MgmtEvent& e) noexcept {
const MgmtEvtNewLongTermKey& event = *static_cast<const MgmtEvtNewLongTermKey *>(&e);
- const MgmtLongTermKeyInfo& ltk_info = event.getLongTermKey();
+ const MgmtLongTermKey& ltk_info = event.getLongTermKey();
BTDeviceRef device = findConnectedDevice(ltk_info.address, ltk_info.address_type);
if( nullptr != device ) {
const bool ok = ltk_info.enc_size > 0 && ltk_info.key_type != MgmtLTKType::NONE;
@@ -2385,7 +2441,7 @@ 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();
+ const MgmtIdentityResolvingKey& irk = event.getIdentityResolvingKey();
if( adapterInfo.addressAndType.address == irk.address && adapterInfo.addressAndType.type == irk.address_type ) {
// setPrivacy ...
visibleAddressAndType.address = randomAddress;
@@ -2397,9 +2453,8 @@ void BTAdapter::mgmtEvNewIdentityResolvingKeyMgmt(const MgmtEvent& e) noexcept {
} 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",
+ // Handled via SMP
+ WORDY_PRINT("BTAdapter::mgmt:NewIdentityResolvingKey(dev_id %d): Device found (Resolvable): %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",
@@ -2682,6 +2737,8 @@ void BTAdapter::sendDevicePairingState(const BTDeviceRef& device, const SMPPairi
SMPKeyBin key = SMPKeyBin::create(*device);
if( key.isValid() ) {
addSMPKeyBin( std::make_shared<SMPKeyBin>(key), true /* write_file */ );
+ } else {
+ WARN_PRINT("(dev_id %d): created SMPKeyBin invalid: %s", dev_id, key.toString().c_str());
}
} else {
// pre-paired, refresh PairingData of BTDevice (perhaps a new instance)
@@ -2689,7 +2746,7 @@ void BTAdapter::sendDevicePairingState(const BTDeviceRef& device, const SMPPairi
if( nullptr != key ) {
bool res = device->setSMPKeyBin(*key);
if( !res ) {
- WARN_PRINT("(dev_id %d): device::setSMPKeyBin() failed %d, %s", res, key->toString().c_str());
+ WARN_PRINT("(dev_id %d): device::setSMPKeyBin() failed %d, %s", dev_id, res, key->toString().c_str());
}
}
}
diff --git a/src/direct_bt/BTDevice.cpp b/src/direct_bt/BTDevice.cpp
index 5f1d48cf..afed6e42 100644
--- a/src/direct_bt/BTDevice.cpp
+++ b/src/direct_bt/BTDevice.cpp
@@ -64,7 +64,8 @@ BTDevice::BTDevice(const ctor_cookie& cc, BTAdapter & a, EInfoReport const & r)
smp_events(0),
pairing_data { },
ts_creation(ts_last_discovery),
- addressAndType{r.getAddress(), r.getAddressType()}
+ visibleAddressAndType{r.getAddress(), r.getAddressType()},
+ addressAndType(visibleAddressAndType)
{
(void)cc;
@@ -134,9 +135,10 @@ EInfoReportRef BTDevice::getEIRScanRsp() noexcept {
std::string BTDevice::toString(bool includeDiscoveredServices) const noexcept {
const uint64_t t0 = jau::getCurrentMilliseconds();
jau::sc_atomic_critical sync(sync_data);
+ std::string resaddr_s = visibleAddressAndType != addressAndType ? ", visible "+visibleAddressAndType.toString() : "";
std::shared_ptr<const EInfoReport> eir_ = eir;
std::string eir_s = BTRole::Slave == getRole() ? ", "+eir_->toString( includeDiscoveredServices ) : "";
- std::string out("Device["+to_string(getRole())+", "+addressAndType.toString()+", name['"+name+
+ std::string out("Device["+to_string(getRole())+", "+addressAndType.toString()+resaddr_s+", name['"+name+
"'], age[total "+std::to_string(t0-ts_creation)+", ldisc "+std::to_string(t0-ts_last_discovery)+", lup "+std::to_string(t0-ts_last_update)+
"]ms, connected["+std::to_string(allowDisconnect)+"/"+std::to_string(isConnected)+", handle "+jau::to_hexstring(hciConnHandle)+
", phy[Tx "+direct_bt::to_string(le_phy_tx)+", Rx "+direct_bt::to_string(le_phy_rx)+
@@ -177,6 +179,33 @@ void BTDevice::clearData() noexcept {
// clearSMPStates( false /* connected */); // already done
}
+bool BTDevice::updateIdentityAddress(BDAddressAndType const & identityAddress, bool sendEvent) noexcept {
+ if( BDAddressType::BDADDR_LE_PUBLIC != addressAndType.type && addressAndType != identityAddress ) {
+ addressAndType = identityAddress;
+ adapter.hci.setResolvHCIConnectionAddr(visibleAddressAndType, addressAndType);
+ if( sendEvent ) {
+ std::shared_ptr<BTDevice> sharedInstance = getSharedInstance();
+ if( nullptr == sharedInstance ) {
+ ERR_PRINT("Device unknown to adapter and not tracked: %s", toString().c_str());
+ } else {
+ adapter.sendDeviceUpdated("Address Resolution", sharedInstance, jau::getCurrentMilliseconds(), EIRDataType::BDADDR | EIRDataType::BDADDR_TYPE);
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool BTDevice::updateVisibleAddress(BDAddressAndType const & randomPrivateAddress) noexcept {
+ if( visibleAddressAndType != randomPrivateAddress ) {
+ visibleAddressAndType = randomPrivateAddress;
+ return true;
+ } else {
+ return false;
+ }
+}
+
EIRDataType BTDevice::update(EInfoReport const & data) noexcept {
const std::lock_guard<std::mutex> lock(mtx_eir); // RAII-style acquire and relinquish via destructor
@@ -558,10 +587,15 @@ void BTDevice::notifyConnected(const std::shared_ptr<BTDevice>& sthis, const uin
allowDisconnect = true;
isConnected = true;
hciConnHandle = handle;
+ SMPIOCapability io_cap_pre = pairing_data.ioCap_conn;
if( SMPIOCapability::UNSET == pairing_data.ioCap_conn ) {
pairing_data.ioCap_conn = io_cap;
}
- DBG_PRINT("BTDevice::notifyConnected: End: %s", toString().c_str());
+ DBG_PRINT("BTDevice::notifyConnected: End: io_cap %s: %s -> %s, %s",
+ to_string(io_cap).c_str(),
+ to_string(io_cap_pre).c_str(),
+ to_string(pairing_data.ioCap_conn).c_str(),
+ toString().c_str());
(void)sthis; // not used yet
}
@@ -1566,10 +1600,10 @@ HCIStatusCode BTDevice::uploadKeys() noexcept {
// LTKs
{
jau::darray<SMPLongTermKey> ltks;
- if( ( SMPKeyType::ENC_KEY & pairing_data.keys_init_has ) != SMPKeyType::NONE ) {
+ if( is_set(pairing_data.keys_init_has, SMPKeyType::ENC_KEY) ) {
ltks.push_back(pairing_data.ltk_init);
}
- if( ( SMPKeyType::ENC_KEY & pairing_data.keys_resp_has ) != SMPKeyType::NONE ) {
+ if( is_set(pairing_data.keys_resp_has, SMPKeyType::ENC_KEY) ) {
ltks.push_back(pairing_data.ltk_resp);
}
if( ltks.size() > 0 ) {
@@ -1584,10 +1618,10 @@ HCIStatusCode BTDevice::uploadKeys() noexcept {
// IRKs
{
jau::darray<SMPIdentityResolvingKey> irks;
- if( ( SMPKeyType::ID_KEY & pairing_data.keys_init_has ) != SMPKeyType::NONE ) {
+ if( is_set(pairing_data.keys_init_has, SMPKeyType::ID_KEY) ) {
irks.push_back(pairing_data.irk_init);
}
- if( ( SMPKeyType::ID_KEY & pairing_data.keys_resp_has ) != SMPKeyType::NONE ) {
+ if( is_set(pairing_data.keys_resp_has, SMPKeyType::ID_KEY) ) {
irks.push_back(pairing_data.irk_resp);
}
if( irks.size() > 0 ) {
@@ -1607,13 +1641,13 @@ HCIStatusCode BTDevice::uploadKeys() noexcept {
if( BTRole::Slave == btRole ) {
// Remote device is slave (peripheral, responder), we are master (initiator)
- if( ( SMPKeyType::LINK_KEY & pairing_data.keys_init_has ) != SMPKeyType::NONE ) {
+ if( is_set(pairing_data.keys_init_has, SMPKeyType::LINK_KEY) ) {
res = mngr->uploadLinkKey(adapter.dev_id, addressAndType, pairing_data.lk_init);
DBG_PRINT("BTDevice::uploadKeys.LK[adapter master]: %s", to_string(res).c_str());
}
} else {
// Remote device is master (initiator), we are slave (peripheral, responder)
- if( ( SMPKeyType::LINK_KEY & pairing_data.keys_resp_has ) != SMPKeyType::NONE ) {
+ if( is_set(pairing_data.keys_resp_has, SMPKeyType::LINK_KEY) ) {
res = mngr->uploadLinkKey(adapter.dev_id, addressAndType, pairing_data.lk_resp);
DBG_PRINT("BTDevice::uploadKeys.LK[adapter slave]: %s", to_string(res).c_str());
}
@@ -1667,8 +1701,12 @@ void BTDevice::setIdentityResolvingKey(const SMPIdentityResolvingKey& irk) noexc
bool BTDevice::matches_irk(BDAddressAndType rpa) noexcept {
// self_is_responder == true: responder's IRK info (LL slave), else the initiator's (LL master)
const bool self_is_responder = BTRole::Slave == btRole;
- SMPIdentityResolvingKey irk = getIdentityResolvingKey(self_is_responder);
- return irk.matches(rpa.address); // irk.id_address == this->addressAndType
+ if( is_set(self_is_responder ? pairing_data.keys_resp_has : pairing_data.keys_init_has, SMPKeyType::ID_KEY) ) {
+ SMPIdentityResolvingKey irk = getIdentityResolvingKey(self_is_responder);
+ return irk.matches(rpa.address); // irk.id_address == this->addressAndType
+ } else {
+ return false;
+ }
}
SMPSignatureResolvingKey BTDevice::getSignatureResolvingKey(const bool responder) const noexcept {
diff --git a/src/direct_bt/HCIHandler.cpp b/src/direct_bt/HCIHandler.cpp
index d7654d6c..1abb2b2d 100644
--- a/src/direct_bt/HCIHandler.cpp
+++ b/src/direct_bt/HCIHandler.cpp
@@ -77,6 +77,20 @@ __pack( struct hci_rp_status {
__u8 status;
} );
+HCIHandler::HCIConnectionRef HCIHandler::setResolvHCIConnectionAddr(jau::darray<HCIConnectionRef> &list,
+ const BDAddressAndType& visibleAddressAndType,
+ const BDAddressAndType& addressAndType) noexcept {
+ const std::lock_guard<std::recursive_mutex> lock(mtx_connectionList); // RAII-style acquire and relinquish via destructor
+ auto end = list.end();
+ for (auto it = list.begin(); it != end; ++it) {
+ HCIConnectionRef conn = *it;
+ if ( conn->equals(visibleAddressAndType) ) {
+ conn->setResolvAddrAndType(addressAndType);
+ return conn; // done
+ }
+ }
+ return nullptr;
+}
HCIHandler::HCIConnectionRef HCIHandler::addOrUpdateHCIConnection(jau::darray<HCIConnectionRef> &list,
const BDAddressAndType& addressAndType, const uint16_t handle) noexcept {
diff --git a/src/direct_bt/SMPKeyBin.cpp b/src/direct_bt/SMPKeyBin.cpp
index 23c6d230..a08c76d5 100644
--- a/src/direct_bt/SMPKeyBin.cpp
+++ b/src/direct_bt/SMPKeyBin.cpp
@@ -75,31 +75,31 @@ SMPKeyBin SMPKeyBin::create(const BTDevice& device) {
const SMPKeyType keys_resp = device.getAvailableSMPKeys(true /* responder */);
const SMPKeyType keys_init = device.getAvailableSMPKeys(false /* responder */);
- if( ( SMPKeyType::ENC_KEY & keys_init ) != SMPKeyType::NONE ) {
+ if( is_set(keys_init, SMPKeyType::ENC_KEY) ) {
smpKeyBin.setLTKInit( device.getLongTermKey(false /* responder */) );
}
- if( ( SMPKeyType::ENC_KEY & keys_resp ) != SMPKeyType::NONE ) {
+ if( is_set(keys_resp, SMPKeyType::ENC_KEY) ) {
smpKeyBin.setLTKResp( device.getLongTermKey(true /* responder */) );
}
- if( ( SMPKeyType::ID_KEY & keys_init ) != SMPKeyType::NONE ) {
+ if( is_set(keys_init, SMPKeyType::ID_KEY) ) {
smpKeyBin.setIRKInit( device.getIdentityResolvingKey(false /* responder */) );
}
- if( ( SMPKeyType::ID_KEY & keys_resp ) != SMPKeyType::NONE ) {
+ if( is_set(keys_resp, SMPKeyType::ID_KEY) ) {
smpKeyBin.setIRKResp( device.getIdentityResolvingKey(true /* responder */) );
}
- if( ( SMPKeyType::SIGN_KEY & keys_init ) != SMPKeyType::NONE ) {
+ if( is_set(keys_init, SMPKeyType::SIGN_KEY) ) {
smpKeyBin.setCSRKInit( device.getSignatureResolvingKey(false /* responder */) );
}
- if( ( SMPKeyType::SIGN_KEY & keys_resp ) != SMPKeyType::NONE ) {
+ if( is_set(keys_resp, SMPKeyType::SIGN_KEY) ) {
smpKeyBin.setCSRKResp( device.getSignatureResolvingKey(true /* responder */) );
}
- if( ( SMPKeyType::LINK_KEY & keys_init ) != SMPKeyType::NONE ) {
+ if( is_set(keys_init, SMPKeyType::LINK_KEY) ) {
smpKeyBin.setLKInit( device.getLinkKey(false /* responder */) );
}
- if( ( SMPKeyType::LINK_KEY & keys_resp ) != SMPKeyType::NONE ) {
+ if( is_set(keys_resp, SMPKeyType::LINK_KEY) ) {
smpKeyBin.setLKResp( device.getLinkKey(true /* responder */) );
}
} else {