summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/direct_bt/BTAdapter.hpp43
-rw-r--r--examples/dbt_constants.hpp2
-rw-r--r--examples/dbt_peripheral00.cpp25
-rw-r--r--java/jau/direct_bt/DBTAdapter.java3
-rw-r--r--java/jni/direct_bt/DBTAdapter.cxx11
-rw-r--r--java/org/direct_bt/BTAdapter.java18
-rwxr-xr-xscripts/run-native-example.sh1
-rw-r--r--src/direct_bt/BTAdapter.cpp239
8 files changed, 233 insertions, 109 deletions
diff --git a/api/direct_bt/BTAdapter.hpp b/api/direct_bt/BTAdapter.hpp
index 06d64478..cd3ba90a 100644
--- a/api/direct_bt/BTAdapter.hpp
+++ b/api/direct_bt/BTAdapter.hpp
@@ -332,12 +332,19 @@ namespace direct_bt {
typedef jau::cow_darray<impl::StatusListenerPair> statusListenerList_t;
statusListenerList_t statusListenerList;
+ // Storing SMPKeyBin entries, referenced by their remote address, i.e. BTDevice address.
+ std::string key_path;
+ typedef std::shared_ptr<SMPKeyBin> SMPKeyBinRef;
+ typedef jau::darray<SMPKeyBinRef> key_list_t;
+ key_list_t key_list;
+
DBGattServerRef gattServerData = nullptr;
mutable std::mutex mtx_discoveredDevices;
mutable std::mutex mtx_connectedDevices;
mutable std::mutex mtx_discovery;
mutable std::mutex mtx_sharedDevices; // final mutex of all BTDevice lifecycle
+ mutable std::mutex mtx_keys;
mutable jau::sc_atomic_bool sync_data;
bool updateDataFromHCI() noexcept;
@@ -405,6 +412,13 @@ namespace direct_bt {
std::shared_ptr<BTDevice> getSharedDevice(const BTDevice & device) noexcept;
void removeSharedDevice(const BTDevice & device) noexcept;
+ static SMPKeyBinRef findSMPKeyBin(key_list_t & keys, BDAddressAndType const & remoteAddress) noexcept;
+ static bool removeSMPKeyBin(key_list_t & keys, BDAddressAndType const & remoteAddress, const bool remove_file, const std::string key_path_) noexcept;
+ SMPKeyBinRef findSMPKeyBin(BDAddressAndType const & remoteAddress) noexcept;
+ /** Adding a SMPKeyBin will remove previous entry. */
+ bool addSMPKeyBin(const SMPKeyBinRef& key, const bool write_file) noexcept;
+ bool removeSMPKeyBin(BDAddressAndType const & remoteAddress, const bool remove_file) noexcept;
+
bool mgmtEvNewSettingsMgmt(const MgmtEvent& e) noexcept;
void updateAdapterSettings(const bool off_thread, const AdapterSetting new_settings, const bool sendEvent, const uint64_t timestamp) noexcept;
bool mgmtEvDeviceDiscoveringMgmt(const MgmtEvent& e) noexcept;
@@ -650,20 +664,41 @@ namespace direct_bt {
bool setSecureConnections(const bool enable) noexcept;
/**
+ * Set the adapter's persistent storage directory for SMPKeyBin files.
+ * - if set, all SMPKeyBin instances will be managed and persistent.
+ * - if not set, all SMPKeyBin instances will be transient only.
+ *
+ * When called, all keys within the path will be loaded,
+ * i.e. issuing uploadKeys() for all keys belonging to this BTAdapter.
+ *
+ * Persistent SMPKeyBin management is only functional when BTAdapter is in BTRole::Slave peripheral mode.
+ *
+ * For each SMPKeyBin file one shared BTDevice in BTRole::Master will be instantiated
+ * when uploadKeys() is called.
+ *
+ * @param path persistent storage path to SMPKeyBin files
+ * @see uploadKeys()
+ */
+ void setSMPKeyPath(const std::string path) noexcept;
+
+ /**
* Associate the given SMPKeyBin with the contained remote address, i.e. SMPKeyBin::getRemoteAddrAndType().
*
* Further uploads the Long Term Key (LTK) and Link Key (LK) for a potential upcoming connection,
* if they are contained in the given SMPKeyBin file.
*
* This method is provided to support BTRole::Slave peripheral adapter mode,
- * allowing user to inject all required keys before a connection occurs.
+ * allowing user to inject all required keys after initialize()
*
- * FIXME: Pass keys to BTDevice instance after connection!
+ * One shared BTDevice in BTRole::Master is instantiated.
*
- * @param keys SMPKeyBin file
+ * @param bin SMPKeyBin instance, might be persistent in filesystem
+ * @param write if true, write file to persistent storage, otherwise not
* @return HCIStatusCode::SUCCESS or an error state on failure
+ * @see setSMPKeyPath()
+ * @see BTDevice::uploadKeys()
*/
- HCIStatusCode setSMPKeyBin(const SMPKeyBin& keys) noexcept;
+ HCIStatusCode uploadKeys(SMPKeyBin& bin, const bool write) noexcept;
/**
* Initialize the adapter with default values, including power-on.
diff --git a/examples/dbt_constants.hpp b/examples/dbt_constants.hpp
index 2ff4aaa4..71d6f8f1 100644
--- a/examples/dbt_constants.hpp
+++ b/examples/dbt_constants.hpp
@@ -38,4 +38,6 @@
*/
constexpr const char KEY_PATH[] = "keys";
+constexpr const char ADAPTER_KEY_PATH[] = "dbt_keys";
+
#endif /* DBT_CONSTANTS_HPP */
diff --git a/examples/dbt_peripheral00.cpp b/examples/dbt_peripheral00.cpp
index 09fa7a58..8fe81ff9 100644
--- a/examples/dbt_peripheral00.cpp
+++ b/examples/dbt_peripheral00.cpp
@@ -70,7 +70,6 @@ static bool SHOW_UPDATE_EVENTS = false;
static bool startAdvertising(BTAdapter *a, std::string msg);
static bool stopAdvertising(BTAdapter *a, std::string msg);
-static void processConnectedDevice(std::shared_ptr<BTDevice> device);
static void processReadyDevice(std::shared_ptr<BTDevice> device);
static void processDisconnectedDevice(std::shared_ptr<BTDevice> device);
@@ -216,9 +215,6 @@ class MyAdapterStatusListener : public AdapterStatusListener {
void deviceConnected(std::shared_ptr<BTDevice> device, const uint16_t handle, const uint64_t timestamp) override {
fprintf_td(stderr, "****** CONNECTED: %s\n", device->toString(true).c_str());
- std::thread sd(::processConnectedDevice, device); // @suppress("Invalid arguments")
- sd.detach();
-
(void)handle;
(void)timestamp;
}
@@ -232,9 +228,6 @@ class MyAdapterStatusListener : public AdapterStatusListener {
// next: deviceReady(..)
break;
case SMPPairingState::FAILED: {
- const bool res = SMPKeyBin::remove(KEY_PATH, *device);
- fprintf_td(stderr, "****** PAIRING_STATE: state %s; Remove key file %s, res %d\n",
- to_string(state).c_str(), SMPKeyBin::getFilename(KEY_PATH, *device).c_str(), res);
// next: deviceReady() or deviceDisconnected(..)
} break;
case SMPPairingState::REQUESTED_BY_RESPONDER:
@@ -479,16 +472,6 @@ static bool stopAdvertising(BTAdapter *a, std::string msg) {
return HCIStatusCode::SUCCESS == status;
}
-static void processConnectedDevice(std::shared_ptr<BTDevice> device) {
- fprintf_td(stderr, "****** Connected Device: Start %s\n", device->toString().c_str());
-
- // Already Connected - Can't Do!
- // HCIStatusCode res = SMPKeyBin::readAndApply(KEY_PATH, *device, BTSecurityLevel::UNSET, true /* verbose */);
- // fprintf_td(stderr, "****** CONNECTED: SMPKeyBin::readAndApply(..) result %s\n", to_string(res).c_str());
-
- fprintf_td(stderr, "****** Connected Device: End %s\n", device->toString().c_str());
-}
-
static void processDisconnectedDevice(std::shared_ptr<BTDevice> device) {
fprintf_td(stderr, "****** Disconnected Device: Start %s\n", device->toString().c_str());
@@ -505,8 +488,6 @@ static void processDisconnectedDevice(std::shared_ptr<BTDevice> device) {
static void processReadyDevice(std::shared_ptr<BTDevice> device) {
fprintf_td(stderr, "****** Processing Ready Device: Start %s\n", device->toString().c_str());
- SMPKeyBin::createAndWrite(*device, KEY_PATH, false /* overwrite */, true /* verbose */);
-
fprintf_td(stderr, "****** Processing Ready Device: End %s\n", device->toString().c_str());
}
@@ -562,11 +543,7 @@ static bool initAdapter(std::shared_ptr<BTAdapter>& adapter) {
fprintf_td(stderr, "initAdapter: Set Default LE PHY: status %s: Tx %s, Rx %s\n",
to_string(res).c_str(), to_string(Tx).c_str(), to_string(Rx).c_str());
}
- {
- std::vector<SMPKeyBin> keys = SMPKeyBin::readAllForLocalAdapter(adapter->getAddressAndType(), KEY_PATH, true /* verbose_ */);
- jau::nsize_t count = SMPKeyBin::applyAll(keys, *adapter);
- fprintf_td(stderr, "initAdapter: Set %d SMPKeyBin, successfully taken %d SMPKeyBin entries\n", keys.size(), count);
- }
+ adapter->setSMPKeyPath(ADAPTER_KEY_PATH);
std::shared_ptr<AdapterStatusListener> asl( std::make_shared<MyAdapterStatusListener>() );
adapter->addStatusListener( asl );
diff --git a/java/jau/direct_bt/DBTAdapter.java b/java/jau/direct_bt/DBTAdapter.java
index a6dd1254..a4d36c85 100644
--- a/java/jau/direct_bt/DBTAdapter.java
+++ b/java/jau/direct_bt/DBTAdapter.java
@@ -274,6 +274,9 @@ public class DBTAdapter extends DBTObject implements BTAdapter
public native boolean setSecureConnections(final boolean enable);
@Override
+ public native void setSMPKeyPath(final String path);
+
+ @Override
public final HCIStatusCode initialize() {
return initialize(BTMode.DUAL);
}
diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx
index 524f2064..9af80f24 100644
--- a/java/jni/direct_bt/DBTAdapter.cxx
+++ b/java/jni/direct_bt/DBTAdapter.cxx
@@ -910,6 +910,17 @@ jboolean Java_jau_direct_1bt_DBTAdapter_setSecureConnections(JNIEnv *env, jobjec
return JNI_FALSE;
}
+void Java_jau_direct_1bt_DBTAdapter_setSMPKeyPath(JNIEnv *env, jobject obj, jstring jpath) {
+ try {
+ BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj);
+ jau::JavaGlobalObj::check(adapter->getJavaObject(), E_FILE_LINE);
+ std::string path = jau::from_jstring_to_string(env, jpath);
+ adapter->setSMPKeyPath(path);
+ } catch(...) {
+ rethrow_and_raise_java_exception(env);
+ }
+}
+
jbyte Java_jau_direct_1bt_DBTAdapter_initializeImpl(JNIEnv *env, jobject obj, jbyte jbtMode) {
try {
BTAdapter *adapter = jau::getJavaUplinkObject<BTAdapter>(env, obj);
diff --git a/java/org/direct_bt/BTAdapter.java b/java/org/direct_bt/BTAdapter.java
index f9d222f5..1dc32f17 100644
--- a/java/org/direct_bt/BTAdapter.java
+++ b/java/org/direct_bt/BTAdapter.java
@@ -477,6 +477,24 @@ public interface BTAdapter extends BTObject
boolean setSecureConnections(final boolean enable);
/**
+ * Set the adapter's persistent storage directory for {@link SMPKeyBin} files.
+ * - if set, all {@link SMPKeyBin} instances will be managed and persistent.
+ * - if not set, all {@link SMPKeyBin} instances will be transient only.
+ *
+ * When called, all keys within the path will be loaded,
+ * i.e. issuing {@link BTDevice#uploadKeys(SMPKeyBin, BTSecurityLevel) for all keys belonging to this BTAdapter.
+ *
+ * Persistent {@link SMPKeyBin} management is only functional when {@link BTAdapter} is in {@link BTRole#Slave} peripheral mode.
+ *
+ * For each {@link SMPKeyBin} file one shared {@link BTDevice} in {@link BTRole#Master} will be instantiated
+ * when uploadKeys() is called.
+ *
+ * @param path persistent storage path to {@link SMPKeyBin} files
+ * @see BTDevice#uploadKeys(SMPKeyBin, BTSecurityLevel)
+ */
+ void setSMPKeyPath(final String path);
+
+ /**
* Initialize the adapter with default values, including power-on.
* <p>
* Method shall be issued on the desired adapter found via {@link BTManager.ChangedAdapterSetListener}.
diff --git a/scripts/run-native-example.sh b/scripts/run-native-example.sh
index 192c74b3..e7f93e62 100755
--- a/scripts/run-native-example.sh
+++ b/scripts/run-native-example.sh
@@ -172,6 +172,7 @@ runit() {
echo LD_LIBRARY_PATH=`pwd`/lib $EXE_WRAPPER bin/${exename} "$@"
mkdir -p keys
+ mkdir -p dbt_keys
if [ "${run_setcap}" -eq "1" ]; then
runit_setcap "$@"
diff --git a/src/direct_bt/BTAdapter.cpp b/src/direct_bt/BTAdapter.cpp
index cec26514..a033ee1c 100644
--- a/src/direct_bt/BTAdapter.cpp
+++ b/src/direct_bt/BTAdapter.cpp
@@ -336,6 +336,11 @@ void BTAdapter::close() noexcept {
const std::lock_guard<std::mutex> lock(mtx_sharedDevices); // RAII-style acquire and relinquish via destructor
sharedDevices.clear();
}
+ {
+ const std::lock_guard<std::mutex> lock(mtx_keys); // RAII-style acquire and relinquish via destructor
+ key_list.clear();
+ key_path.clear();
+ }
valid = false;
DBG_PRINT("BTAdapter::close: XXX");
}
@@ -448,88 +453,59 @@ bool BTAdapter::setSecureConnections(const bool enable) noexcept {
return enable == isAdapterSettingBitSet(new_settings, AdapterSetting::SECURE_CONN);
}
-HCIStatusCode BTAdapter::setSMPKeyBin(const SMPKeyBin& keys) noexcept {
- if( keys.getLocalAddrAndType() != adapterInfo.addressAndType ) {
- if( keys.getVerbose() ) {
+void BTAdapter::setSMPKeyPath(const std::string path) noexcept {
+ jau::sc_atomic_critical sync(sync_data); // redundant due to mutex-lock cache-load operation, leaving it for doc
+ key_path = path;
+
+ std::vector<SMPKeyBin> keys = SMPKeyBin::readAllForLocalAdapter(getAddressAndType(), key_path, jau::environment::get().debug /* verbose_ */);
+ for(SMPKeyBin f : keys) {
+ uploadKeys(f, false /* write */);
+ }
+}
+
+HCIStatusCode BTAdapter::uploadKeys(SMPKeyBin& bin, const bool write) noexcept {
+ if( bin.getLocalAddrAndType() != adapterInfo.addressAndType ) {
+ if( bin.getVerbose() ) {
jau::PLAIN_PRINT(true, "BTAdapter::setSMPKeyBin: Adapter address not matching: %s, %s",
- keys.toString().c_str(), toString().c_str());
+ bin.toString().c_str(), toString().c_str());
}
return HCIStatusCode::INVALID_PARAMS;
}
- /**
- if( isConnected ) {
- ERR_PRINT("BTDevice::setLongTermKeyInfo: Already connected: %s", toString().c_str());
- return HCIStatusCode::CONNECTION_ALREADY_EXISTS;
- } */
- // FIXME: Pass keys to BTDevice instance after connection!
-#if USE_LINUX_BT_SECURITY
+ EInfoReport ad_report;
+ {
+ ad_report.setSource( EInfoReport::Source::NA );
+ ad_report.setTimestamp( jau::getCurrentMilliseconds() );
+ ad_report.setAddressType( bin.getRemoteAddrAndType().type );
+ ad_report.setAddress( bin.getRemoteAddrAndType().address );
+ }
+ // Enforce BTRole::Master on new device,
+ // since this functionality is only for local being BTRole::Slave peripheral!
+ std::shared_ptr<BTDevice> device = BTDevice::make_shared(*this, ad_report);
+ device->btRole = BTRole::Master;
+ addSharedDevice(device);
+
HCIStatusCode res;
BTManager & mngr = getManager();
- res = mngr.unpairDevice(dev_id, keys.getRemoteAddrAndType(), false /* disconnect */);
+ res = mngr.unpairDevice(dev_id, bin.getRemoteAddrAndType(), false /* disconnect */);
if( HCIStatusCode::SUCCESS != res && HCIStatusCode::NOT_PAIRED != res ) {
ERR_PRINT("BTAdapter::setSMPKeyBin: Unpair device failed: %s, %s",
- keys.getRemoteAddrAndType().toString().c_str(), toString().c_str());
- }
- if( keys.hasLTKInit() ) {
- res = mngr.uploadLongTermKey(dev_id, keys.getRemoteAddrAndType(), keys.getLTKInit());
- if( HCIStatusCode::SUCCESS != res ) {
- if( keys.getVerbose() ) {
- jau::PLAIN_PRINT(true, "BTAdapter::setSMPKeyBin: Upload LTK initiator failed: %s, %s",
- keys.toString().c_str(), toString().c_str());
- }
- return res;
- }
+ bin.getRemoteAddrAndType().toString().c_str(), toString().c_str());
}
- if( keys.hasLTKResp() ) {
- res = mngr.uploadLongTermKey(dev_id, keys.getRemoteAddrAndType(), keys.getLTKResp());
- if( HCIStatusCode::SUCCESS != res ) {
- if( keys.getVerbose() ) {
- jau::PLAIN_PRINT(true, "BTAdapter::setSMPKeyBin: Upload LTK responder failed: %s, %s",
- keys.toString().c_str(), toString().c_str());
- }
- return res;
+
+ res = device->uploadKeys(bin, BTSecurityLevel::NONE);
+ if( HCIStatusCode::SUCCESS != res ) {
+ WARN_PRINT("(dev_id %d): Upload SMPKeyBin failed %s, %s (removing file)",
+ dev_id, to_string(res).c_str(), bin.toString().c_str());
+ if( key_path.size() > 0 ) {
+ bin.remove(key_path);
}
- }
- if( BDAddressType::BDADDR_BREDR != keys.getRemoteAddrAndType().type ) {
- // Not supported
- DBG_PRINT("BTAdapter::setSMPKeyBin: Upload LK for LE address not supported -> ignored");
+ return res;
} else {
- if( BTRole::Master == btRole ) {
- // Remote device is slave (peripheral), we are master (initiator)
- if( keys.hasLKInit() ) {
- res = mngr.uploadLinkKey(dev_id, keys.getRemoteAddrAndType(), keys.getLKInit());
- if( HCIStatusCode::SUCCESS != res ) {
- if( keys.getVerbose() ) {
- jau::PLAIN_PRINT(true, "BTAdapter::setSMPKeyBin: Upload LK initiator failed: %s, %s",
- keys.toString().c_str(), toString().c_str());
- }
- return res;
- }
- }
- } else {
- // Remote device is master (central), we are slave (peripheral)
- if( keys.hasLKResp() ) {
- res = mngr.uploadLinkKey(dev_id, keys.getRemoteAddrAndType(), keys.getLKResp());
- if( HCIStatusCode::SUCCESS != res ) {
- if( keys.getVerbose() ) {
- jau::PLAIN_PRINT(true, "BTAdapter::setSMPKeyBin: Upload LK responder failed: %s, %s",
- keys.toString().c_str(), toString().c_str());
- }
- return res;
- }
- }
- }
- }
- if( keys.getVerbose() ) {
- jau::PLAIN_PRINT(true, "BTAdapter::setSMPKeyBin: Upload OK: %s, %s",
- keys.toString().c_str(), toString().c_str());
+ DBG_PRINT("BTAdapter::setSMPKeyBin(dev_id %d): Upload OK: %s, %s",
+ dev_id, bin.toString().c_str(), toString().c_str());
}
+ addSMPKeyBin( std::make_shared<SMPKeyBin>(bin), write); // PERIPHERAL_ADAPTER_MANAGES_SMP_KEYS
return HCIStatusCode::SUCCESS;
-#elif SMP_SUPPORTED_BY_OS
- return HCIStatusCode::NOT_SUPPORTED;
-#else
- return HCIStatusCode::NOT_SUPPORTED;
-#endif
}
HCIStatusCode BTAdapter::initialize(const BTMode btMode) noexcept {
@@ -1086,7 +1062,6 @@ bool BTAdapter::removeDiscoveredDevice(const BDAddressAndType & addressAndType)
return false;
}
-
int BTAdapter::removeDiscoveredDevices() noexcept {
const std::lock_guard<std::mutex> lock(mtx_discoveredDevices); // RAII-style acquire and relinquish via destructor
jau::sc_atomic_critical sync(sync_data); // redundant due to mutex-lock cache-load operation, leaving it for doc
@@ -1117,6 +1092,8 @@ jau::darray<std::shared_ptr<BTDevice>> BTAdapter::getDiscoveredDevices() const n
return res;
}
+// *************************************************
+
bool BTAdapter::addSharedDevice(std::shared_ptr<BTDevice> const &device) noexcept {
const std::lock_guard<std::mutex> lock(mtx_sharedDevices); // RAII-style acquire and relinquish via destructor
if( nullptr != findDevice(sharedDevices, *device) ) {
@@ -1149,6 +1126,8 @@ std::shared_ptr<BTDevice> BTAdapter::findSharedDevice (const EUI48 & address, co
return findDevice(sharedDevices, address, addressType);
}
+// *************************************************
+
void BTAdapter::removeDevice(BTDevice & device) noexcept {
WORDY_PRINT("DBTAdapter::removeDevice: Start %s", toString().c_str());
removeAllStatusListener(device);
@@ -1168,6 +1147,61 @@ void BTAdapter::removeDevice(BTDevice & device) noexcept {
// *************************************************
+BTAdapter::SMPKeyBinRef BTAdapter::findSMPKeyBin(key_list_t & keys, BDAddressAndType const & remoteAddress) noexcept {
+ const jau::nsize_t size = keys.size();
+ for (jau::nsize_t i = 0; i < size; ++i) {
+ SMPKeyBinRef& k = keys[i];
+ if ( nullptr != k && remoteAddress == k->getRemoteAddrAndType() ) {
+ return k;
+ }
+ }
+ return nullptr;
+}
+bool BTAdapter::removeSMPKeyBin(key_list_t & keys, BDAddressAndType const & remoteAddress, const bool remove_file, const std::string key_path_) noexcept {
+ for (auto it = keys.begin(); it != keys.end(); ++it) {
+ const SMPKeyBinRef& k = *it;
+ if ( nullptr != k && remoteAddress == k->getRemoteAddrAndType() ) {
+ DBG_PRINT("BTAdapter::removeSMPKeyBin(file %d): %s", remove_file, k->toString().c_str());
+ if( remove_file && key_path_.size() > 0 ) {
+ if( !k->remove(key_path_) ) {
+ WARN_PRINT("Failed removal of SMPKeyBin file: %s", k->getFilename(key_path_).c_str());
+ }
+ }
+ keys.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+BTAdapter::SMPKeyBinRef BTAdapter::findSMPKeyBin(BDAddressAndType const & remoteAddress) noexcept {
+ const std::lock_guard<std::mutex> lock(mtx_keys); // RAII-style acquire and relinquish via destructor
+ jau::sc_atomic_critical sync(sync_data); // redundant due to mutex-lock cache-load operation, leaving it for doc
+ return findSMPKeyBin(key_list, remoteAddress);
+}
+bool BTAdapter::addSMPKeyBin(const SMPKeyBinRef& key, const bool write_file) noexcept {
+ const std::lock_guard<std::mutex> lock(mtx_keys); // RAII-style acquire and relinquish via destructor
+ jau::sc_atomic_critical sync(sync_data); // redundant due to mutex-lock cache-load operation, leaving it for doc
+ removeSMPKeyBin(key_list, key->getRemoteAddrAndType(), write_file /* remove_file */, key_path);
+ if( jau::environment::get().debug ) {
+ key->setVerbose(true);
+ DBG_PRINT("BTAdapter::addSMPKeyBin(file %d): %s", write_file, key->toString().c_str());
+ }
+ key_list.push_back( key );
+ if( write_file && key_path.size() > 0 ) {
+ if( !key->write(key_path, true /* overwrite */) ) {
+ WARN_PRINT("Failed write of SMPKeyBin file: %s", key->getFilename(key_path).c_str());
+ }
+ }
+ return true;
+}
+bool BTAdapter::removeSMPKeyBin(BDAddressAndType const & remoteAddress, const bool remove_file) noexcept {
+ const std::lock_guard<std::mutex> lock(mtx_keys); // RAII-style acquire and relinquish via destructor
+ jau::sc_atomic_critical sync(sync_data); // redundant due to mutex-lock cache-load operation, leaving it for doc
+ return removeSMPKeyBin(key_list, remoteAddress, remove_file, key_path);
+}
+
+// *************************************************
+
HCIStatusCode BTAdapter::startAdvertising(DBGattServerRef gattServerData_,
const uint16_t adv_interval_min, const uint16_t adv_interval_max,
const AD_PDU_Type adv_type,
@@ -1492,6 +1526,7 @@ bool BTAdapter::mgmtEvDeviceConnectedHCI(const MgmtEvent& e) noexcept {
ad_report.read_data(event.getData(), event.getDataSize());
}
int new_connect = 0;
+ bool slave_unpair = false;
std::shared_ptr<BTDevice> device = findConnectedDevice(event.getAddress(), event.getAddressType());
if( nullptr == device ) {
device = findDiscoveredDevice(event.getAddress(), event.getAddressType());
@@ -1505,25 +1540,30 @@ bool BTAdapter::mgmtEvDeviceConnectedHCI(const MgmtEvent& e) noexcept {
if( nullptr != device ) {
addDiscoveredDevice(device); // connected devices must be in shared + discovered list
new_connect = 2;
+ slave_unpair = BTRole::Slave == getRole();
}
}
if( nullptr == device ) {
+ // (new_connect = 3) a whitelist auto-connect w/o previous discovery, or
+ // (new_connect = 4) we are a peripheral being connected by a remote client
device = BTDevice::make_shared(*this, ad_report);
addDiscoveredDevice(device);
addSharedDevice(device);
- if( BTRole::Slave == getRole() ) {
- new_connect = 4; // slave adapter (peripheral), got connected by remote client
- /**
- * Without unpair in SC mode, the peripheral fails the DHKey Check.
- * TODO: Provide a persistent pre-pairing mechanism via SMPKeyBin.
- */
- HCIStatusCode res = mgmt.unpairDevice(dev_id, device->getAddressAndType(), false /* disconnect */);
+ new_connect = BTRole::Master == getRole() ? 3 : 4;
+ slave_unpair = BTRole::Slave == getRole();
+ }
+ if( slave_unpair ) {
+ /**
+ * Without unpair in SC mode (or key pre-pairing), the peripheral fails the DHKey Check.
+ */
+ const SMPKeyBinRef key = findSMPKeyBin( device->getAddressAndType() ); // PERIPHERAL_ADAPTER_MANAGES_SMP_KEYS
+ if( nullptr == key ) {
+ // No pre-pairing -> unpair
+ HCIStatusCode res = mgmt.unpairDevice(dev_id, device->getAddressAndType(), false /* disconnect */);
if( HCIStatusCode::SUCCESS != res && HCIStatusCode::NOT_PAIRED != res ) {
- WARN_PRINT("BTAdapter::EventHCI:DeviceConnected(dev_id %d, new_connect %d): Unpair device failed: %s, %s",
+ WARN_PRINT("(dev_id %d, new_connect %d): Unpair device failed: %s, %s",
dev_id, new_connect, to_string(res).c_str(), device->getAddressAndType().toString().c_str());
}
- } else {
- new_connect = 3; // master adapter, whitelist auto-connect w/o previous discovery
}
}
@@ -1672,7 +1712,7 @@ bool BTAdapter::mgmtEvDeviceDisconnectedHCI(const MgmtEvent& e) noexcept {
device->toString().c_str());
unlockConnect(*device);
- device->notifyDisconnected();
+ device->notifyDisconnected(); // -> unpair()
removeConnectedDevice(*device);
if( !device->isConnSecurityAutoEnabled() ) {
@@ -1691,6 +1731,18 @@ bool BTAdapter::mgmtEvDeviceDisconnectedHCI(const MgmtEvent& e) noexcept {
});
removeDiscoveredDevice(device->addressAndType); // ensure device will cause a deviceFound event after disconnect
}
+ if( BTRole::Slave == getRole() ) {
+ // PERIPHERAL_ADAPTER_MANAGES_SMP_KEYS
+ SMPKeyBinRef key = findSMPKeyBin(device->getAddressAndType());
+ if( nullptr != key ) {
+ const HCIStatusCode res = device->uploadKeys(*key, BTSecurityLevel::NONE);
+ if( HCIStatusCode::SUCCESS != res ) {
+ WARN_PRINT("(dev_id %d): Upload SMPKeyBin failed %s, %s (removing file)",
+ dev_id, to_string(res).c_str(), key->toString().c_str());
+ removeSMPKeyBin(device->getAddressAndType(), true /* remove_file */);
+ }
+ }
+ }
} else {
WORDY_PRINT("BTAdapter::EventHCI:DeviceDisconnected(dev_id %d): Device not tracked: %s",
dev_id, event.toString().c_str());
@@ -2080,6 +2132,31 @@ bool BTAdapter::hciSMPMsgCallback(const BDAddressAndType & addressAndType,
void BTAdapter::sendDevicePairingState(std::shared_ptr<BTDevice> device, const SMPPairingState state, const PairingMode mode, uint64_t timestamp) noexcept
{
+ if( BTRole::Slave == getRole() ) {
+ // PERIPHERAL_ADAPTER_MANAGES_SMP_KEYS
+ if( SMPPairingState::COMPLETED == state ) {
+ // Pairing completed
+ if( PairingMode::PRE_PAIRED != mode ) {
+ // newly paired -> store keys
+ SMPKeyBin key = SMPKeyBin::create(*device);
+ if( key.isValid() ) {
+ addSMPKeyBin( std::make_shared<SMPKeyBin>(key), true /* write_file */ );
+ }
+ } else {
+ // pre-paired, refresh PairingData of BTDevice (perhaps a new instance)
+ const SMPKeyBinRef key = findSMPKeyBin( device->getAddressAndType() );
+ 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());
+ }
+ }
+ }
+ } else if( SMPPairingState::FAILED == state ) {
+ // Pairing failed
+ removeSMPKeyBin(device->getAddressAndType(), true /* remove_file */);
+ }
+ }
int i=0;
jau::for_each_fidelity(statusListenerList, [&](impl::StatusListenerPair &p) {
try {