diff options
author | Sven Gothel <[email protected]> | 2020-11-24 21:05:27 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-11-24 21:05:27 +0100 |
commit | cc475330fd173ee0e38b4a9a8cb5205fa2136bed (patch) | |
tree | c6c97247cbd8f0304473caf1865f366b3ea9cab9 | |
parent | 9f932fc51e5bed3d1a059131667191f56c20d7fb (diff) |
DBTDevice: Clarify setConn* Security parameter API: Provide more versatile overloaded variant and simplified API entries.
setConnSecurityLevel(..) no more sets SMPIOCapability, only advise in API doc to avoid complexity.
-rw-r--r-- | api/direct_bt/DBTAdapter.hpp | 19 | ||||
-rw-r--r-- | api/direct_bt/DBTDevice.hpp | 143 | ||||
-rw-r--r-- | examples/direct_bt_scanner10/dbt_scanner10.cpp | 14 | ||||
-rw-r--r-- | examples/java/DBTScanner10.java | 8 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTDevice.java | 6 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTDevice.cxx | 4 | ||||
-rw-r--r-- | java/org/tinyb/BluetoothDevice.java | 79 | ||||
-rw-r--r-- | java/tinyb/dbus/DBusDevice.java | 2 | ||||
-rw-r--r-- | src/direct_bt/DBTAdapter.cpp | 17 | ||||
-rw-r--r-- | src/direct_bt/DBTDevice.cpp | 82 |
10 files changed, 277 insertions, 97 deletions
diff --git a/api/direct_bt/DBTAdapter.hpp b/api/direct_bt/DBTAdapter.hpp index 868c8485..ec042cee 100644 --- a/api/direct_bt/DBTAdapter.hpp +++ b/api/direct_bt/DBTAdapter.hpp @@ -249,9 +249,9 @@ namespace direct_bt { uint16_t min_interval, uint16_t max_interval, uint16_t latency, uint16_t supervision_timeout); friend HCIStatusCode DBTDevice::connectBREDR(const uint16_t pkt_type, const uint16_t clock_offset, const uint8_t role_switch); - friend bool DBTDevice::setConnSecurityLevel(const BTSecurityLevel sec_level, const bool blocking) noexcept; - friend bool DBTDevice::setConnIOCapability(const SMPIOCapability io_cap, const bool blocking) noexcept; - friend bool DBTDevice::setConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap, const bool blocking) noexcept; + friend bool DBTDevice::setConnSecurityLevel(const BTSecurityLevel sec_level) noexcept; + friend bool DBTDevice::setConnIOCapability(const SMPIOCapability io_cap, bool& blocking, SMPIOCapability& pre_io_cap) noexcept; + friend bool DBTDevice::setConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap, bool& blocking, SMPIOCapability& pre_io_cap) noexcept; friend void DBTDevice::processL2CAPSetup(std::shared_ptr<DBTDevice> sthis); friend bool DBTDevice::updatePairingState(std::shared_ptr<DBTDevice> sthis, SMPPairingState state, std::shared_ptr<MgmtEvent> evt) noexcept; friend void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_ptr<const SMPPDUMsg> msg, const HCIACLData::l2cap_frame& source) noexcept; @@ -261,14 +261,19 @@ namespace direct_bt { /** * Sets the given SMPIOCapability for the next DBTDevice::connectLE() or DBTDevice::connectBREDR(). * <p> - * The SMPIOCapability value will be reset to its previous value when connection is completed or failed. + * The ::SMPIOCapability value will be reset to its previous value when connection is completed or failed. * </p> - * @param io_cap SMPIOCapability to be applied - * @param blocking if true, blocks until previous setting is completed, + * <p> + * A value of ::SMPIOCapability::UNSET will be ignored and method returns immediately. + * </p> + * @param[in] io_cap ::SMPIOCapability to be applied + * @param[in,out] blocking if true, blocks until previous setting is completed, * i.e. until connection has been completed or failed. * Otherwise returns immediately with false if previous connection result is still pending. + * On return, this parameter will be set to true if failure was caused by blocking or timeout, otherwise set to false. + * @param[out] pre_io_cap return the previous set ::SMPIOCapability value if successful */ - bool setConnIOCapability(const DBTDevice & device, const SMPIOCapability io_cap, const bool blocking) noexcept; + bool setConnIOCapability(const DBTDevice & device, const SMPIOCapability io_cap, bool& blocking, SMPIOCapability& pre_io_cap) noexcept; bool resetConnIOCapability(const DBTDevice & device) noexcept; bool resetConnIOCapability(const DBTDevice & device, SMPIOCapability& pre_io_cap) noexcept; bool isConnIOCapabilitySet() const noexcept { return nullptr != io_capability_device_ptr; } diff --git a/api/direct_bt/DBTDevice.hpp b/api/direct_bt/DBTDevice.hpp index 2ceaf62c..83aed534 100644 --- a/api/direct_bt/DBTDevice.hpp +++ b/api/direct_bt/DBTDevice.hpp @@ -430,64 +430,155 @@ namespace direct_bt { HCIStatusCode disconnect(const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION ) noexcept; /** - * Set the ::BTSecurityLevel used to connect to this device. + * Set the ::BTSecurityLevel used to connect to this device on the upcoming connection. * <p> - * Method returns false if this device has already being connected, + * Method returns false if ::BTSecurityLevel::UNSET has been given, + * operation fails, this device has already being connected, * or DBTDevice::connectLE() or DBTDevice::connectBREDR() has been issued already. * </p> * <p> - * To ensure consistent no authentication setup,<br> - * implementation will set ::SMPIOCapability::NO_INPUT_NO_OUTPUT if sec_level <= ::BTSecurityLevel::ENC_ONLY<br> - * and DBTDevice::setConnIOCapability() has not been used. + * To ensure a consistent authentication setup, + * it is advised to set ::SMPIOCapability::NO_INPUT_NO_OUTPUT for sec_level <= ::BTSecurityLevel::ENC_ONLY + * using setConnSecurity() as well as an IO capable ::SMPIOCapability value + * for ::BTSecurityLevel::ENC_AUTH or ::BTSecurityLevel::ENC_AUTH_FIPS. * </p> - * @param sec_level ::BTSecurityLevel to be applied - * @param blocking if true, blocks until previous ::SMPIOCapability setting is completed, - * i.e. until connection has been completed or failed. - * Otherwise returns immediately with false if previous connection result is still pending. - * @return + * @param sec_level ::BTSecurityLevel to be applied, ::BTSecurityLevel::UNSET will be ignored and method fails. + * @see ::BTSecurityLevel + * @see ::SMPIOCapability + * @see getConnSecurityLevel() + * @see setConnIOCapability() + * @see getConnIOCapability() + * @see setConnSecurity() */ - bool setConnSecurityLevel(const BTSecurityLevel sec_level, const bool blocking) noexcept; + bool setConnSecurityLevel(const BTSecurityLevel sec_level) noexcept; /** - * Return the ::BTSecurityLevel, determined when connection is established. + * Return the ::BTSecurityLevel, determined when the connection is established. + * @see ::BTSecurityLevel + * @see ::SMPIOCapability + * @see setConnSecurityLevel() + * @see setConnIOCapability() + * @see getConnIOCapability() + * @see setConnSecurity() */ BTSecurityLevel getConnSecurityLevel() const noexcept { return pairing_data.sec_level_conn; } /** - * Sets the given ::SMPIOCapability used to connect to this device. + * Sets the given ::SMPIOCapability used to connect to this device temporarily for the adapter. * <p> - * Method returns false if operation fails, this device has already being connected, + * Method returns false if ::SMPIOCapability::UNSET has been given, + * operation fails, this device has already being connected, * or DBTDevice::connectLE() or DBTDevice::connectBREDR() has been issued already. * </p> * <p> * The ::SMPIOCapability value will be reset for the adapter to its previous value when connection is completed or failed. * </p> - * @param io_cap ::SMPIOCapability to be applied - * @param blocking if true, blocks until previous ::SMPIOCapability setting is completed, + * @param[in] io_cap ::SMPIOCapability to be applied, ::SMPIOCapability::UNSET will be ignored and method fails. + * @param[in,out] blocking if true, blocks until previous ::SMPIOCapability setting is completed, * i.e. until connection has been completed or failed. - * Otherwise returns immediately with false if previous connection result is still pending. + * Otherwise returns immediately with false if previous connection result is still pending on the adapter.<br> + * On return, this parameter will be set to true if failure was caused by blocking or timeout, otherwise set to false. + * @param[out] pre_io_cap return the previous set ::SMPIOCapability value if successful + * @see ::BTSecurityLevel + * @see ::SMPIOCapability + * @see setConnSecurityLevel() + * @see getConnSecurityLevel() + * @see getConnIOCapability() + * @see setConnSecurity() */ - bool setConnIOCapability(const SMPIOCapability io_cap, const bool blocking=true) noexcept; + bool setConnIOCapability(const SMPIOCapability io_cap, bool& blocking, SMPIOCapability& pre_io_cap) noexcept; + + /** + * Sets the given ::SMPIOCapability used to connect to this device temporarily for the adapter. + * <p> + * Method returns false if ::SMPIOCapability::UNSET has been given, + * operation fails, this device has already being connected, + * or DBTDevice::connectLE() or DBTDevice::connectBREDR() has been issued already. + * </p> + * <p> + * The ::SMPIOCapability value will be reset for the adapter to its previous value when connection is completed or failed. + * </p> + * @param[in] io_cap ::SMPIOCapability to be applied, ::SMPIOCapability::UNSET will be ignored and method fails. + * @param[in] blocking if true, blocks until previous ::SMPIOCapability setting is completed, + * i.e. until connection has been completed or failed. + * Otherwise returns immediately with false if previous connection result is still pending on the adapter. + * @see ::BTSecurityLevel + * @see ::SMPIOCapability + * @see setConnSecurityLevel() + * @see getConnSecurityLevel() + * @see getConnIOCapability() + * @see setConnSecurity() + */ + bool setConnIOCapability(const SMPIOCapability io_cap, const bool blocking) noexcept { + SMPIOCapability pre_io_cap { SMPIOCapability::UNSET }; + bool blocking_in_out = blocking; + return setConnIOCapability(io_cap, blocking_in_out, pre_io_cap); + } /** - * Sets the given ::BTSecurityLevel and ::SMPIOCapability used to connect to this device. + * Sets the given ::BTSecurityLevel (on the upcoming connection) and ::SMPIOCapability (temporarily for the adapter) + * used to connect to this device if successful, otherwise method doesn't change either value. * <p> - * Method returns false if operation fails, this device has already being connected, + * Method returns false if ::BTSecurityLevel::UNSET or ::SMPIOCapability::UNSET has been given, + * operation fails, this device has already being connected, * or DBTDevice::connectLE() or DBTDevice::connectBREDR() has been issued already. * </p> * <p> * The ::SMPIOCapability value will be reset for the adapter to its previous value when connection is completed or failed. * </p> - * @param sec_level ::BTSecurityLevel to be applied - * @param io_cap ::SMPIOCapability to be applied - * @param blocking if true, blocks until previous ::SMPIOCapability setting is completed, + * @param[in] sec_level ::BTSecurityLevel to be applied, ::BTSecurityLevel::UNSET will be ignored and method fails. + * @param[in] io_cap ::SMPIOCapability to be applied, ::SMPIOCapability::UNSET will be ignored and method fails. + * @param[in,out] blocking if true, blocks until previous ::SMPIOCapability setting is completed, * i.e. until connection has been completed or failed. - * Otherwise returns immediately with false if previous connection result is still pending. + * Otherwise returns immediately with false if previous connection result is still pending on the adapter.<br> + * On return, this parameter will be set to true if failure was caused by blocking or timeout, otherwise set to false. + * @param[out] pre_io_cap return the previous set ::SMPIOCapability value if successful + * @see ::BTSecurityLevel + * @see ::SMPIOCapability + * @see setConnSecurityLevel() + * @see getConnSecurityLevel() + * @see setConnIOCapability() + * @see getConnIOCapability() */ - bool setConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap, const bool blocking=true) noexcept; + bool setConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap, bool& blocking, SMPIOCapability& pre_io_cap) noexcept; + + /** + * Sets the given ::BTSecurityLevel (on the upcoming connection) and ::SMPIOCapability (temporarily for the adapter) + * used to connect to this device if successful, otherwise method doesn't change either value. + * <p> + * Method returns false if ::BTSecurityLevel::UNSET or ::SMPIOCapability::UNSET has been given, + * operation fails, this device has already being connected, + * or DBTDevice::connectLE() or DBTDevice::connectBREDR() has been issued already. + * </p> + * <p> + * The ::SMPIOCapability value will be reset for the adapter to its previous value when connection is completed or failed. + * </p> + * @param[in] sec_level ::BTSecurityLevel to be applied, ::BTSecurityLevel::UNSET will be ignored and method fails. + * @param[in] io_cap ::SMPIOCapability to be applied, ::SMPIOCapability::UNSET will be ignored and method fails. + * @param[in] blocking if true, blocks until previous ::SMPIOCapability setting is completed, + * i.e. until connection has been completed or failed. + * Otherwise returns immediately with false if previous connection result is still pending on the adapter. + * @see ::BTSecurityLevel + * @see ::SMPIOCapability + * @see setConnSecurityLevel() + * @see getConnSecurityLevel() + * @see setConnIOCapability() + * @see getConnIOCapability() + */ + bool setConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap, const bool blocking) noexcept { + SMPIOCapability pre_io_cap { SMPIOCapability::UNSET }; + bool blocking_in_out = blocking; + return setConnSecurity(sec_level, io_cap, blocking_in_out, pre_io_cap); + } /** - * Return the set ::SMPIOCapability value, determined when connection is established. + * Return the set ::SMPIOCapability value, determined when the connection is established. + * @see ::BTSecurityLevel + * @see ::SMPIOCapability + * @see setConnSecurityLevel() + * @see getConnSecurityLevel() + * @see setConnIOCapability() + * @see setConnSecurity() */ SMPIOCapability getConnIOCapability() const noexcept { return pairing_data.ioCap_conn; } diff --git a/examples/direct_bt_scanner10/dbt_scanner10.cpp b/examples/direct_bt_scanner10/dbt_scanner10.cpp index bcda886a..74565da3 100644 --- a/examples/direct_bt_scanner10/dbt_scanner10.cpp +++ b/examples/direct_bt_scanner10/dbt_scanner10.cpp @@ -76,8 +76,8 @@ static bool QUIET = false; static std::vector<EUI48> waitForDevices; -const static uint32_t NO_PASSKEY = 0xffffffffU; -static uint32_t pairing_passkey = NO_PASSKEY; +const static int NO_PASSKEY = -1; +static int pairing_passkey = NO_PASSKEY; static BTSecurityLevel sec_level = BTSecurityLevel::UNSET; static SMPIOCapability io_capabilities = SMPIOCapability::UNSET; @@ -250,7 +250,7 @@ class MyAdapterStatusListener : public AdapterStatusListener { break; case SMPPairingState::PASSKEY_EXPECTED: { if( pairing_passkey != NO_PASSKEY ) { - std::thread dc(&DBTDevice::setPairingPasskey, device, pairing_passkey); // @suppress("Invalid arguments") + std::thread dc(&DBTDevice::setPairingPasskey, device, static_cast<uint32_t>(pairing_passkey)); // @suppress("Invalid arguments") dc.detach(); } /* else { std::thread dc(&DBTDevice::setPairingPasskeyNegative, device); // @suppress("Invalid arguments") @@ -367,7 +367,11 @@ static void connectDiscoveredDevice(std::shared_ptr<DBTDevice> device) { if( BTSecurityLevel::UNSET < sec_level && SMPIOCapability::UNSET != io_capabilities ) { device->setConnSecurity(sec_level, io_capabilities, true /* blocking */); } else if( BTSecurityLevel::UNSET < sec_level ) { - device->setConnSecurityLevel(sec_level, true /* blocking */); + if( BTSecurityLevel::ENC_ONLY >= sec_level ) { + device->setConnSecurity(sec_level, SMPIOCapability::NO_INPUT_NO_OUTPUT, true /* blocking */); + } else { + device->setConnSecurityLevel(sec_level); + } } else if( SMPIOCapability::UNSET != io_capabilities ) { device->setConnIOCapability(io_capabilities, true /* blocking */); } @@ -807,7 +811,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "SHOW_UPDATE_EVENTS %d\n", SHOW_UPDATE_EVENTS); fprintf(stderr, "QUIET %d\n", QUIET); fprintf(stderr, "btmode %s\n", getBTModeString(btMode).c_str()); - fprintf(stderr, "passkey %u\n", pairing_passkey); + fprintf(stderr, "passkey %d\n", pairing_passkey); fprintf(stderr, "seclevel %s\n", getBTSecurityLevelString(sec_level).c_str()); fprintf(stderr, "iocap %s\n", getSMPIOCapabilityString(io_capabilities).c_str()); fprintf(stderr, "characteristic-id: %s\n", charIdentifier.c_str()); diff --git a/examples/java/DBTScanner10.java b/examples/java/DBTScanner10.java index 33e799ca..1cbfb426 100644 --- a/examples/java/DBTScanner10.java +++ b/examples/java/DBTScanner10.java @@ -77,7 +77,7 @@ public class DBTScanner10 { final List<String> waitForDevices = new ArrayList<String>(); - static final int NO_PASSKEY = 0xffffffff; + static final int NO_PASSKEY = -1; int pairing_passkey = NO_PASSKEY; BTSecurityLevel sec_level = BTSecurityLevel.UNSET; SMPIOCapability io_capabilities = SMPIOCapability.UNSET; @@ -295,7 +295,11 @@ public class DBTScanner10 { if( BTSecurityLevel.UNSET.value < sec_level.value && SMPIOCapability.UNSET.value != io_capabilities.value ) { device.setConnSecurity(sec_level, io_capabilities, true /* blocking */); } else if( BTSecurityLevel.UNSET.value < sec_level.value ) { - device.setConnSecurityLevel(sec_level, true /* blocking */); + if( BTSecurityLevel.ENC_ONLY.value >= sec_level.value ) { + device.setConnSecurity(sec_level, SMPIOCapability.NO_INPUT_NO_OUTPUT, true /* blocking */); + } else { + device.setConnSecurityLevel(sec_level); + } } else if( SMPIOCapability.UNSET.value != io_capabilities.value ) { device.setConnIOCapability(io_capabilities, true /* blocking */); } diff --git a/java/direct_bt/tinyb/DBTDevice.java b/java/direct_bt/tinyb/DBTDevice.java index 2895f123..c35fae23 100644 --- a/java/direct_bt/tinyb/DBTDevice.java +++ b/java/direct_bt/tinyb/DBTDevice.java @@ -335,10 +335,10 @@ public class DBTDevice extends DBTObject implements BluetoothDevice } @Override - public final boolean setConnSecurityLevel(final BTSecurityLevel sec_level, final boolean blocking) { - return setConnSecurityLevelImpl(sec_level.value, blocking); + public final boolean setConnSecurityLevel(final BTSecurityLevel sec_level) { + return setConnSecurityLevelImpl(sec_level.value); } - private final native boolean setConnSecurityLevelImpl(final byte sec_level, final boolean blocking); + private final native boolean setConnSecurityLevelImpl(final byte sec_level); @Override public final BTSecurityLevel getConnSecurityLevel() { diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx index ec4e6676..417c6fd7 100644 --- a/java/jni/direct_bt/DBTDevice.cxx +++ b/java/jni/direct_bt/DBTDevice.cxx @@ -379,12 +379,12 @@ jbyte Java_direct_1bt_tinyb_DBTDevice_connectLEImpl1(JNIEnv *env, jobject obj, } -jboolean Java_direct_1bt_tinyb_DBTDevice_setConnSecurityLevelImpl(JNIEnv *env, jobject obj, jbyte jsec_level, jboolean jblocking) { +jboolean Java_direct_1bt_tinyb_DBTDevice_setConnSecurityLevelImpl(JNIEnv *env, jobject obj, jbyte jsec_level) { try { DBTDevice *device = getJavaUplinkObject<DBTDevice>(env, obj); JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE); - return device->setConnSecurityLevel( getBTSecurityLevel( static_cast<uint8_t>(jsec_level) ), JNI_TRUE == jblocking ); + return device->setConnSecurityLevel( getBTSecurityLevel( static_cast<uint8_t>(jsec_level) )); } catch(...) { rethrow_and_raise_java_exception(env); } diff --git a/java/org/tinyb/BluetoothDevice.java b/java/org/tinyb/BluetoothDevice.java index 53355a51..0bc82160 100644 --- a/java/org/tinyb/BluetoothDevice.java +++ b/java/org/tinyb/BluetoothDevice.java @@ -194,74 +194,107 @@ public interface BluetoothDevice extends BluetoothObject boolean pair() throws BluetoothException; /** - * Set the {@link BTSecurityLevel} used to connect to this device. + * Set the {@link BTSecurityLevel} used to connect to this device on the upcoming connection. * <p> - * Method returns false if this device has already being connected, + * Method returns false if {@link BTSecurityLevel#UNSET} has been given, + * operation fails, this device has already being connected, * or {@link #connectLE(short, short, short, short, short, short) connectLE} or {@link #connect()} has been issued already. * </p> * <p> - * To ensure consistent no authentication setup,<br> - * implementation will set {@link SMPIOCapability#NO_INPUT_NO_OUTPUT} if sec_level <= {@link BTSecurityLevel#ENC_ONLY}<br> - * and {@link #setConnIOCapability(SMPIOCapability, boolean)} not used. + * To ensure a consistent authentication setup, + * it is advised to set {@link SMPIOCapability#NO_INPUT_NO_OUTPUT} for sec_level <= {@link BTSecurityLevel#ENC_ONLY} + * using {@link #setConnSecurity(BTSecurityLevel, SMPIOCapability, boolean) setConnSecurity(..)} + * as well as an IO capable {@link SMPIOCapability} value + * for {@link BTSecurityLevel#ENC_AUTH} or {@link BTSecurityLevel#ENC_AUTH_FIPS}. * </p> - * @param sec_level {@link BTSecurityLevel} to be applied - * @param blocking if true, blocks until previous {@link SMPIOCapability} setting is completed, - * i.e. until connection has been completed or failed. - * Otherwise returns immediately with false if previous connection result is still pending. + * @param sec_level {@link BTSecurityLevel} to be applied, {@link BTSecurityLevel#UNSET} will be ignored and method fails. * @return * @since 2.1.0 * @implNote not implemented in tinyb.dbus + * @see BTSecurityLevel + * @see SMPIOCapability + * @see #getConnSecurityLevel() + * @see #setConnIOCapability(SMPIOCapability, boolean) + * @see #getConnIOCapability() + * @see #setConnSecurity(BTSecurityLevel, SMPIOCapability, boolean) */ - boolean setConnSecurityLevel(final BTSecurityLevel sec_level, boolean blocking); + boolean setConnSecurityLevel(final BTSecurityLevel sec_level); /** - * Return the {@link BTSecurityLevel}, determined when connection is established. + * Return the {@link BTSecurityLevel}, determined when the connection is established. * @since 2.1.0 * @implNote not implemented in tinyb.dbus + * @see BTSecurityLevel + * @see SMPIOCapability + * @see #setConnSecurityLevel(BTSecurityLevel) + * @see #setConnIOCapability(SMPIOCapability, boolean) + * @see #getConnIOCapability() + * @see #setConnSecurity(BTSecurityLevel, SMPIOCapability, boolean) */ BTSecurityLevel getConnSecurityLevel(); /** - * Sets the given {@link SMPIOCapability} used to connect to this device. + * Sets the given {@link SMPIOCapability} used to connect to this device temporarily for the adapter. * <p> - * Method returns false if operation fails, this device has already being connected, + * Method returns false if {@link SMPIOCapability#UNSET} has been given, + * operation fails, this device has already being connected, * or {@link #connectLE(short, short, short, short, short, short) connectLE} or {@link #connect()} has been issued already. * </p> * <p> - * The {@link SMPIOCapability} value will be reset to its previous value when connection is completed or failed. + * The {@link SMPIOCapability} value will be reset for the adapter to its previous value when connection is completed or failed. * </p> - * @param io_cap {@link SMPIOCapability} to be applied + * @param io_cap {@link SMPIOCapability} to be applied, {@link SMPIOCapability#UNSET} will be ignored and method fails. * @param blocking if true, blocks until previous {@link SMPIOCapability} setting is completed, * i.e. until connection has been completed or failed. - * Otherwise returns immediately with false if previous connection result is still pending. + * Otherwise returns immediately with false if previous connection result is still pending on the adapter. * @since 2.1.0 * @implNote not implemented in tinyb.dbus + * @see BTSecurityLevel + * @see SMPIOCapability + * @see #setConnSecurityLevel(BTSecurityLevel) + * @see #getConnSecurityLevel() + * @see #getConnIOCapability() + * @see #setConnSecurity(BTSecurityLevel, SMPIOCapability, boolean) */ boolean setConnIOCapability(final SMPIOCapability io_cap, final boolean blocking); /** - * Sets the given {@link BTSecurityLevel} and {@link SMPIOCapability} used to connect to this device. + * Sets the given {@link BTSecurityLevel} (on the upcoming connection) and {@link SMPIOCapability} (temporarily for the adapter) + * used to connect to this device if successful, otherwise method doesn't change either value. * <p> - * Method returns false if operation fails, this device has already being connected, + * Method returns false if {@link BTSecurityLevel#UNSET} or {@link SMPIOCapability#UNSET} has been given, + * operation fails, this device has already being connected, * or {@link #connectLE(short, short, short, short, short, short) connectLE} or {@link #connect()} has been issued already. * </p> * <p> - * The {@link SMPIOCapability} value will be reset to its previous value when connection is completed or failed. + * The {@link SMPIOCapability} value will be reset for the adapter to its previous value when connection is completed or failed. * </p> - * @param sec_level {@link BTSecurityLevel} to be applied - * @param io_cap {@link SMPIOCapability} to be applied + * @param sec_level {@link BTSecurityLevel} to be applied, {@link BTSecurityLevel#UNSET} will be ignored and method fails. + * @param io_cap {@link SMPIOCapability} to be applied, {@link SMPIOCapability#UNSET} will be ignored and method fails. * @param blocking if true, blocks until previous {@link SMPIOCapability} setting is completed, * i.e. until connection has been completed or failed. - * Otherwise returns immediately with false if previous connection result is still pending. + * Otherwise returns immediately with false if previous connection result is still pending on the adapter. * @since 2.1.0 * @implNote not implemented in tinyb.dbus + * @see BTSecurityLevel + * @see SMPIOCapability + * @see #setConnSecurityLevel(BTSecurityLevel) + * @see #getConnSecurityLevel() + * @see #setConnIOCapability(SMPIOCapability, boolean) + * @see #getConnIOCapability() */ boolean setConnSecurity(final BTSecurityLevel sec_level, final SMPIOCapability io_cap, final boolean blocking); /** - * Return the {@link SMPIOCapability} value, determined when connection is established. + * Return the {@link SMPIOCapability} value, determined when the connection is established. * @since 2.1.0 * @implNote not implemented in tinyb.dbus + * @see BTSecurityLevel + * @see SMPIOCapability + * @see #setConnSecurityLevel(BTSecurityLevel) + * @see #getConnSecurityLevel() + * @see #setConnIOCapability(SMPIOCapability, boolean) + * @see #setConnSecurity(BTSecurityLevel, SMPIOCapability, boolean) */ SMPIOCapability getConnIOCapability(); diff --git a/java/tinyb/dbus/DBusDevice.java b/java/tinyb/dbus/DBusDevice.java index 526abe62..242bd1eb 100644 --- a/java/tinyb/dbus/DBusDevice.java +++ b/java/tinyb/dbus/DBusDevice.java @@ -110,7 +110,7 @@ public class DBusDevice extends DBusObject implements BluetoothDevice public native boolean pair() throws BluetoothException; @Override - public final boolean setConnSecurityLevel(final BTSecurityLevel sec_level, final boolean blocking) { return false; } // FIXME + public final boolean setConnSecurityLevel(final BTSecurityLevel sec_level) { return false; } // FIXME @Override public final BTSecurityLevel getConnSecurityLevel() { return BTSecurityLevel.UNSET; } // FIXME diff --git a/src/direct_bt/DBTAdapter.cpp b/src/direct_bt/DBTAdapter.cpp index 783ef04e..9604a359 100644 --- a/src/direct_bt/DBTAdapter.cpp +++ b/src/direct_bt/DBTAdapter.cpp @@ -354,7 +354,11 @@ bool DBTAdapter::setPowered(bool value) noexcept { return mgmt.setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, value ? 1 : 0, current_settings); } -bool DBTAdapter::setConnIOCapability(const DBTDevice & device, const SMPIOCapability io_cap, const bool blocking) noexcept { +bool DBTAdapter::setConnIOCapability(const DBTDevice & device, const SMPIOCapability io_cap, bool& blocking, SMPIOCapability& pre_io_cap) noexcept { + if( SMPIOCapability::UNSET == io_cap ) { + blocking = false; + return false; + } const DBTDevice * exp_null_device = nullptr; // C++11, exp as value since C++20 const uint32_t timeout_ms = 10000; // FIXME: Configurable? const uint32_t poll_period_ms = 125; @@ -362,21 +366,20 @@ bool DBTAdapter::setConnIOCapability(const DBTDevice & device, const SMPIOCapabi while( !io_capability_device_ptr.compare_exchange_strong(exp_null_device, &device) ) { if( blocking ) { if( timeout_ms <= td ) { + blocking = true; return false; } std::this_thread::sleep_for(std::chrono::milliseconds(poll_period_ms)); td += poll_period_ms; } else { + blocking = true; return false; } } - SMPIOCapability o; - const bool res = mgmt.setIOCapability(dev_id, io_cap, o); - DBG_PRINT("DBTAdapter::setConnIOCapability: result %d: %s -> %s, %s", - res, getSMPIOCapabilityString(o).c_str(), getSMPIOCapabilityString(io_cap).c_str(), - device.toString(false).c_str()); + blocking = false; + const bool res = mgmt.setIOCapability(dev_id, io_cap, pre_io_cap); if( res ) { - io_capability_defaultval = o; + io_capability_defaultval = pre_io_cap; return true; } else { io_capability_device_ptr = nullptr; diff --git a/src/direct_bt/DBTDevice.cpp b/src/direct_bt/DBTDevice.cpp index 7ff0a05f..9720c278 100644 --- a/src/direct_bt/DBTDevice.cpp +++ b/src/direct_bt/DBTDevice.cpp @@ -660,44 +660,84 @@ void DBTDevice::hciSMPMsgCallback(std::shared_ptr<DBTDevice> sthis, std::shared_ DBG_PRINT("DBTDevice:hci:SMP.6: End %s", toString(false).c_str()); } -bool DBTDevice::setConnSecurityLevel(const BTSecurityLevel sec_level, const bool blocking) noexcept { - DBG_PRINT("DBTDevice::setSecurityLevel: %s -> %s, %s", - getBTSecurityLevelString(pairing_data.sec_level_user).c_str(), - getBTSecurityLevelString(sec_level).c_str(), toString(false).c_str()); +bool DBTDevice::setConnSecurityLevel(const BTSecurityLevel sec_level) noexcept { + if( BTSecurityLevel::UNSET == sec_level ) { + DBG_PRINT("DBTAdapter::setConnSecurityLevel: lvl %s, invalid value.", getBTSecurityLevelString(sec_level).c_str()); + return false; + } if( !isValid() || isConnected || allowDisconnect ) { + DBG_PRINT("DBTDevice::setConnSecurityLevel: lvl %s failed, invalid state %s", + getBTSecurityLevelString(sec_level).c_str(), toString(false).c_str()); return false; } + const BTSecurityLevel old_sec_level = pairing_data.sec_level_user; pairing_data.sec_level_user = sec_level; + const bool res = true; - if( BTSecurityLevel::ENC_ONLY >= sec_level && !adapter.isConnIOCapabilitySet() ) - { - // Adjust SMPIOCapability to match the no_auth BTSecurityLevel <= BTSecurityLevel::ENC_ONLY, - // if connect hasn't been issued and setIOCapability() not used yet. - return setConnIOCapability( SMPIOCapability::NO_INPUT_NO_OUTPUT, blocking); - } else { - return true; - } + DBG_PRINT("DBTDevice::setConnSecurityLevel: result %d: lvl %s -> %s, %s", res, + getBTSecurityLevelString(old_sec_level).c_str(), + getBTSecurityLevelString(sec_level).c_str(), + toString(false).c_str()); + return res; } -bool DBTDevice::setConnIOCapability(const SMPIOCapability io_cap, const bool blocking) noexcept { +bool DBTDevice::setConnIOCapability(const SMPIOCapability io_cap, bool& blocking, SMPIOCapability& pre_io_cap) noexcept { + if( SMPIOCapability::UNSET == io_cap ) { + DBG_PRINT("DBTDevice::setConnIOCapability: io %s, invalid value.", getSMPIOCapabilityString(io_cap).c_str()); + return false; + } + if( !isValid() || isConnected || allowDisconnect ) { + DBG_PRINT("DBTDevice::setConnIOCapability: io %s failed, invalid state %s", + getSMPIOCapabilityString(io_cap).c_str(), toString(false).c_str()); return false; } - return adapter.setConnIOCapability(*this, io_cap, blocking); + + const bool blocking_call = blocking; + const bool res = adapter.setConnIOCapability(*this, io_cap, blocking, pre_io_cap); + + DBG_PRINT("DBTDevice::setConnIOCapability: result %d (blocked %d): io %s -> %s (blocking %d), %s", + res, blocking, + getSMPIOCapabilityString(pre_io_cap).c_str(), getSMPIOCapabilityString(io_cap).c_str(), + blocking_call, toString(false).c_str()); + + return res; } -bool DBTDevice::setConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap, const bool blocking) noexcept { - DBG_PRINT("DBTDevice::setConnSecurity: %s -> %s, %s, %s", - getBTSecurityLevelString(pairing_data.sec_level_user).c_str(), - getBTSecurityLevelString(sec_level).c_str(), - getSMPIOCapabilityString(io_cap).c_str(), toString(false).c_str()); +bool DBTDevice::setConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap, bool& blocking, SMPIOCapability& pre_io_cap) noexcept { + if( BTSecurityLevel::UNSET == sec_level ) { + DBG_PRINT("DBTAdapter::setConnSecurity: lvl %s, invalid value.", getBTSecurityLevelString(sec_level).c_str()); + return false; + } + if( SMPIOCapability::UNSET == io_cap ) { + DBG_PRINT("DBTDevice::setConnSecurity: io %s, invalid value.", getSMPIOCapabilityString(io_cap).c_str()); + return false; + } if( !isValid() || isConnected || allowDisconnect ) { + DBG_PRINT("DBTDevice::setConnSecurity: lvl %s, io %s failed, invalid state %s", + getBTSecurityLevelString(sec_level).c_str(), + getSMPIOCapabilityString(io_cap).c_str(), toString(false).c_str()); return false; } - pairing_data.sec_level_user = sec_level; - return adapter.setConnIOCapability(*this, io_cap, blocking); + + const BTSecurityLevel pre_sec_level = pairing_data.sec_level_user; + + const bool blocking_call = blocking; + const bool res = adapter.setConnIOCapability(*this, io_cap, blocking, pre_io_cap); + if( res ) { + pairing_data.sec_level_user = sec_level; + } + + DBG_PRINT("DBTDevice::setConnSecurity: result %d (blocked %d): lvl %s -> %s, io %s -> %s (blocking %d), %s", + res, blocking, + getBTSecurityLevelString(pre_sec_level).c_str(), + getBTSecurityLevelString(pairing_data.sec_level_user).c_str(), + getSMPIOCapabilityString(pre_io_cap).c_str(), getSMPIOCapabilityString(io_cap).c_str(), + blocking_call, toString(false).c_str()); + + return res; } HCIStatusCode DBTDevice::setPairingPasskey(const uint32_t passkey) noexcept { |