diff options
author | Sven Gothel <[email protected]> | 2020-09-22 10:27:06 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-09-22 10:27:06 +0200 |
commit | 8eb3ecb3033b28c5b6cc13807d0948f245ce9729 (patch) | |
tree | cf1443928166d0a2d36a8590deeac72f89c4b942 | |
parent | efd9938140595944dbdf7fa05e653e7cd61a7e7c (diff) |
LE Secure Connections: Initial API to support secure pairing with varying PairingModes (C++, Java)
For now, DBTDevice has a NOP implementation, i.e. returning zero length vectors (or arrays in Java)
for supported and required PairingMode.
The pair(String passkey) simply returns HCIStatusCode::INTERNAL_FAILURE;
Intention is to validate the new API entry with our application.
-rw-r--r-- | api/direct_bt/BTTypes.hpp | 33 | ||||
-rw-r--r-- | api/direct_bt/DBTDevice.hpp | 34 | ||||
-rw-r--r-- | examples/direct_bt_scanner10/dbt_scanner10.cpp | 33 | ||||
-rw-r--r-- | examples/java/ScannerTinyB10.java | 27 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTDevice.java | 76 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTDevice.cxx | 62 | ||||
-rw-r--r-- | java/org/tinyb/BluetoothDevice.java | 56 | ||||
-rw-r--r-- | java/org/tinyb/PairingMode.java | 85 | ||||
-rw-r--r-- | java/tinyb/dbus/DBusDevice.java | 16 | ||||
-rw-r--r-- | src/direct_bt/BTTypes.cpp | 27 | ||||
-rw-r--r-- | src/direct_bt/DBTDevice.cpp | 15 |
11 files changed, 442 insertions, 22 deletions
diff --git a/api/direct_bt/BTTypes.hpp b/api/direct_bt/BTTypes.hpp index d6d09f5a..5994a80f 100644 --- a/api/direct_bt/BTTypes.hpp +++ b/api/direct_bt/BTTypes.hpp @@ -59,11 +59,42 @@ namespace direct_bt { /** * Maps the specified name to a constant of BTMode. * @param name the string name to be mapped to a constant of this enum type. - * @return the corresponding constant of this enum type, using {@link BRMode#NONE} if not supported. + * @return the corresponding constant of this enum type, using {@link BTMode#NONE} if not supported. */ BTMode getBTMode(const std::string & value) noexcept; /** + * Bluetooth secure pairing mode + * <pre> + * BT Core Spec v5.2: Vol 1, Part A, 5 Security Overview + * BT Core Spec v5.2: Vol 1, Part A, 5.4 LE SECURITY + * </pre> + */ + enum class PairingMode : uint8_t { + /** No pairing mode, implying no secure connections, no encryption and no MITM protection. */ + NONE = 0, + /** Just Works. Random key exchange with encryption but no MITM protection. */ + JUST_WORKS = 1, + /** Passkey Entry. A known digit sequence (PIN) must be given as a secret to be validated on the device. Random key exchange with additional secret (PIN) and encryption and MITM protection. */ + PASSKEY_ENTRY = 2, + /** Visual numeric comparison of digit sequence (PIN) shown on both devices, peripheral and host, to be answered. Random key exchange with additional secret (PIN) and encryption and MITM protection. */ + NUMERIC_COMPARISON = 3, + /** Utilizing a second factor secret to be used as a secret, e.g. NFC field. Random key exchange with additional secret (2FA) and encryption and potential MITM protection. */ + OUT_OF_BAND = 4 + }; + inline uint8_t number(const PairingMode rhs) noexcept { + return static_cast<uint8_t>(rhs); + } + std::string getPairingModeString(const PairingMode v) noexcept; + + /** + * Maps the specified name to a constant of PairingMode. + * @param name the string name to be mapped to a constant of this enum type. + * @return the corresponding constant of this enum type, using {@link PairingMode#NONE} if not supported. + */ + PairingMode getPairingMode(const std::string & value) noexcept; + + /** * Meta ScanType as derived from BTMode, * with defined value mask consisting of BDAddressType bits. * <p> diff --git a/api/direct_bt/DBTDevice.hpp b/api/direct_bt/DBTDevice.hpp index 8aa374ac..3113ba63 100644 --- a/api/direct_bt/DBTDevice.hpp +++ b/api/direct_bt/DBTDevice.hpp @@ -336,6 +336,40 @@ namespace direct_bt { } /** + * The device is securely paired with PasskeyEntry or JustWorks. + * <p> + * The device must be connected before pairing, see connectDefault(). + * </p> + * <p> + * If passkey is an empty string, JustWorks method is being used, otherwise PasskeyEntry. + * </p> + * @param passkey optional secret used for PasskeyEntry method. + * Will be encrypted before sending to counterparty. + * Can be an empty string, in which case JustWork method is used. + * + * @return HCIStatusCode::SUCCESS if the command has been accepted, otherwise HCIStatusCode may disclose reason for rejection. + */ + HCIStatusCode pair(const std::string & passkey); + + /** + * Returns a vector of supported PairingMode by the device. + * <p> + * The device must be connected before querying this status, see connectDefault(). FIXME? + * </p> + * @return vector of supported PairingMode, empty if pairing is not supported. + */ + std::vector<PairingMode> getSupportedPairingModes(); + + /** + * Returns a vector of required PairingMode by the device. + * <p> + * The device must be connected before querying this status, see connectDefault(). FIXME? + * </p> + * @return vector of required PairingMode, empty if pairing is not required. + */ + std::vector<PairingMode> getRequiredPairingModes(); + + /** * Disconnects this device via disconnect(..) and * explicitly removes its shared references from the Adapter: * connected-devices, discovered-devices and shared-devices. diff --git a/examples/direct_bt_scanner10/dbt_scanner10.cpp b/examples/direct_bt_scanner10/dbt_scanner10.cpp index 0c08dc25..238c2fd9 100644 --- a/examples/direct_bt_scanner10/dbt_scanner10.cpp +++ b/examples/direct_bt_scanner10/dbt_scanner10.cpp @@ -275,6 +275,39 @@ static void processConnectedDevice(std::shared_ptr<DBTDevice> device) { const uint64_t t1 = getCurrentMilliseconds(); bool success = false; + // Secure Pairing + { + std::vector<PairingMode> spm = device->getSupportedPairingModes(); + fprintf(stderr, "Supported Secure Pairing Modes: "); + std::for_each(spm.begin(), spm.end(), [](PairingMode pm) { fprintf(stderr, "%s, ", getPairingModeString(pm).c_str()); } ); + fprintf(stderr, "\n"); + + std::vector<PairingMode> rpm = device->getRequiredPairingModes(); + fprintf(stderr, "Required Secure Pairing Modes: "); + std::for_each(rpm.begin(), rpm.end(), [](PairingMode pm) { fprintf(stderr, "%s, ", getPairingModeString(pm).c_str()); } ); + fprintf(stderr, "\n"); + + if( spm.end() != std::find (spm.begin(), spm.end(), PairingMode::JUST_WORKS) ) { + const std::vector<int> passkey; // empty for JustWorks + HCIStatusCode res = device->pair(""); // empty for JustWorks + fprintf(stderr, "Secure Pairing Just Works result %s of %s\n", getHCIStatusCodeString(res).c_str(), device->toString().c_str()); + } else if( spm.end() != std::find (spm.begin(), spm.end(), PairingMode::PASSKEY_ENTRY) ) { + HCIStatusCode res = device->pair("111111"); // PasskeyEntry + fprintf(stderr, "Secure Pairing Passkey Entry result %s of %s\n", getHCIStatusCodeString(res).c_str(), device->toString().c_str()); + } else { + fprintf(stderr, "Secure Pairing JUST_WORKS or PASSKEY_ENTRY not supported %s\n", device->toString().c_str()); + } + { + const std::vector<int> passkey; // empty for JustWorks + HCIStatusCode res = device->pair(""); // empty for JustWorks + fprintf(stderr, "T1 Secure Pairing Just Works result %s of %s\n", getHCIStatusCodeString(res).c_str(), device->toString().c_str()); + } + { + HCIStatusCode res = device->pair("111111"); // PasskeyEntry + fprintf(stderr, "T2 Secure Pairing Passkey Entry result %s of %s\n", getHCIStatusCodeString(res).c_str(), device->toString().c_str()); + } + } + // // GATT Service Processing // diff --git a/examples/java/ScannerTinyB10.java b/examples/java/ScannerTinyB10.java index 4ef7c055..1c38a45f 100644 --- a/examples/java/ScannerTinyB10.java +++ b/examples/java/ScannerTinyB10.java @@ -50,6 +50,7 @@ import org.tinyb.EIRDataTypeSet; import org.tinyb.GATTCharacteristicListener; import org.tinyb.HCIStatusCode; import org.tinyb.HCIWhitelistConnectType; +import org.tinyb.PairingMode; import direct_bt.tinyb.DBTManager; @@ -262,6 +263,32 @@ public class ScannerTinyB10 { final long t1 = BluetoothUtils.getCurrentMilliseconds(); boolean success = false; + // Secure Pairing + { + final List<PairingMode> spm = Arrays.asList(device.getSupportedPairingModes()); + println("Supported Secure Pairing Modes: " + spm.toString()); + final List<PairingMode> rpm = Arrays.asList(device.getRequiredPairingModes()); + println("Required Secure Pairing Modes: " + spm.toString()); + + if( spm.contains(PairingMode.JUST_WORKS) ) { + final HCIStatusCode res = device.pair(null); // empty for JustWorks + println("Secure Pairing Just Works result " + res + " of " + device); + } else if( spm.contains(PairingMode.PASSKEY_ENTRY) ) { + final HCIStatusCode res = device.pair("111111"); // PasskeyEntry + println("Secure Pairing Passkey Entry result " + res + " of " + device); + } else { + println("Secure Pairing JUST_WORKS or PASSKEY_ENTRY not supported, but " + spm.toString() + " on " + device); + } + { + final HCIStatusCode res = device.pair(null); // empty for JustWorks + println("T1 Processing Device: Secure Pairing Just Works result " + res + " of " + device); + } + { + final HCIStatusCode res = device.pair("111111"); // PasskeyEntry + println("T2 Processing Device: Secure Pairing Passkey Entry result " + res + " of " + device); + } + } + // // GATT Service Processing // diff --git a/java/direct_bt/tinyb/DBTDevice.java b/java/direct_bt/tinyb/DBTDevice.java index ae361ffc..793d542e 100644 --- a/java/direct_bt/tinyb/DBTDevice.java +++ b/java/direct_bt/tinyb/DBTDevice.java @@ -46,6 +46,7 @@ import org.tinyb.BluetoothType; import org.tinyb.EIRDataTypeSet; import org.tinyb.GATTCharacteristicListener; import org.tinyb.HCIStatusCode; +import org.tinyb.PairingMode; public class DBTDevice extends DBTObject implements BluetoothDevice { @@ -131,6 +132,8 @@ public class DBTDevice extends DBTObject implements BluetoothDevice } @Override public void deviceDisconnected(final BluetoothDevice device, final HCIStatusCode reason, final short handle, final long timestamp) { + devicePaired(false); + if( isConnected.compareAndSet(true, false) ) { clearServiceCache(); synchronized(userCallbackLock) { @@ -164,20 +167,22 @@ public class DBTDevice extends DBTObject implements BluetoothDevice } }; + final private void devicePaired(final boolean _isPaired) { + if( DEBUG ) { + System.err.println("Device.PairedNotification: "+isPaired+" -> "+_isPaired+" on "+DBTDevice.this.toString()); + } + if( isPaired.compareAndSet(!_isPaired, _isPaired) ) { + synchronized(userCallbackLock) { + if( null != userPairedNotificationsCB ) { + userPairedNotificationsCB.run(_isPaired); + } + } + } + } final private BluetoothNotification<Boolean> pairedNotificationsCB = new BluetoothNotification<Boolean>() { @Override public void run(final Boolean value) { - if( DEBUG ) { - System.err.println("Device.PairedNotification: "+isPaired+" -> "+value+" on "+DBTDevice.this.toString()); - } - final boolean _isPaired = value.booleanValue(); - if( isPaired.compareAndSet(!_isPaired, _isPaired) ) { - synchronized(userCallbackLock) { - if( null != userPairedNotificationsCB ) { - userPairedNotificationsCB.run(value); - } - } - } + devicePaired( value.booleanValue() ); } }; @@ -321,10 +326,51 @@ public class DBTDevice extends DBTObject implements BluetoothDevice public final BluetoothDevice clone() { throw new UnsupportedOperationException(); } // FIXME @Override - public boolean pair() throws BluetoothException { throw new UnsupportedOperationException(); } // FIXME + public final boolean pair() throws BluetoothException { + return HCIStatusCode.SUCCESS == pair(null); + } @Override - public boolean cancelPairing() throws BluetoothException { throw new UnsupportedOperationException(); } // FIXME + public HCIStatusCode pair(final String passkey) throws BluetoothException { + if( !getConnected() ) { + throw new IllegalStateException("Device must be connected first: "+toString()); + } + final HCIStatusCode res = HCIStatusCode.get( pairImpl(passkey) ); + + // Secure Pairing (paired == true) has no explicit notification + devicePaired( HCIStatusCode.SUCCESS == res ); + + return res; + } + private native byte pairImpl(final String passkey) throws BluetoothException; + + @Override + public final PairingMode[] getSupportedPairingModes() throws BluetoothException { + final byte[] res0 = getSupportedPairingModesImpl(); + final PairingMode[] res1 = new PairingMode[res0.length]; + for(int i=0; i<res0.length; i++) { + res1[i] = PairingMode.get(res0[i]); + } + return res1; + } + private native byte[] getSupportedPairingModesImpl() throws BluetoothException; + + @Override + public final PairingMode[] getRequiredPairingModes() throws BluetoothException { + final byte[] res0 = getRequiredPairingModesImpl(); + final PairingMode[] res1 = new PairingMode[res0.length]; + for(int i=0; i<res0.length; i++) { + res1[i] = PairingMode.get(res0[i]); + } + return res1; + } + private native byte[] getRequiredPairingModesImpl() throws BluetoothException; + + @Override + public final boolean cancelPairing() throws BluetoothException { + // FIXME: Not supporter (yet) + return false; + } @Override public String getAlias() { return null; } // FIXME @@ -491,7 +537,7 @@ public class DBTDevice extends DBTObject implements BluetoothDevice } @Override - public boolean getPaired() { return isPaired.get(); } + public final boolean getPaired() { return isPaired.get(); } @Override public void enableTrustedNotifications(final BluetoothNotification<Boolean> callback) { @@ -542,7 +588,7 @@ public class DBTDevice extends DBTObject implements BluetoothDevice private native void disableBlockedNotificationsImpl(); private native void setBlockedImpl(final boolean value); - // FIXME: Figure out paired:=true, as currently we only attach to unpaired + // Note that this is only called natively for unpaired, i.e. paired:=false. Using deviceConnected for paired:=true. private native void enablePairedNotificationsImpl(BluetoothNotification<Boolean> callback); private native void disablePairedNotificationsImpl(); diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx index 67b62645..57e18c17 100644 --- a/java/jni/direct_bt/DBTDevice.cxx +++ b/java/jni/direct_bt/DBTDevice.cxx @@ -357,6 +357,66 @@ jbyte Java_direct_1bt_tinyb_DBTDevice_connectImpl__SSSSSS(JNIEnv *env, jobject o return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE); } +jbyte Java_direct_1bt_tinyb_DBTDevice_pairImpl(JNIEnv *env, jobject obj, jstring jpasskey) +{ + try { + DBTDevice *device = getDBTObject<DBTDevice>(env, obj); + JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE); + + const std::string passkey = nullptr != jpasskey ? from_jstring_to_string(env, jpasskey) : std::string(); + HCIStatusCode res = device->pair(passkey); + return (jbyte) number(res); + + } catch(...) { + rethrow_and_raise_java_exception(env); + } + return (jbyte) number(HCIStatusCode::INTERNAL_FAILURE); +} + +jbyteArray Java_direct_1bt_tinyb_DBTDevice_getSupportedPairingModesImpl(JNIEnv *env, jobject obj) { + try { + DBTDevice *device = getDBTObject<DBTDevice>(env, obj); + JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE); + + std::vector<PairingMode> res0 = device->getSupportedPairingModes(); + const size_t value_size = res0.size(); + + uint8_t res1[value_size]; + for(size_t i=0; i < value_size; i++) { + res1[i] = number(res0[i]); + } + jbyteArray jres = env->NewByteArray((jsize)value_size); + env->SetByteArrayRegion(jres, 0, (jsize)value_size, (const jbyte *)res1); + java_exception_check_and_throw(env, E_FILE_LINE); + return jres; + } catch(...) { + rethrow_and_raise_java_exception(env); + } + return JNI_FALSE; +} + +jbyteArray Java_direct_1bt_tinyb_DBTDevice_getRequiredPairingModesImpl(JNIEnv *env, jobject obj) { + try { + DBTDevice *device = getDBTObject<DBTDevice>(env, obj); + JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE); + + std::vector<PairingMode> res0 = device->getRequiredPairingModes(); + const size_t value_size = res0.size(); + + uint8_t res1[value_size]; + for(size_t i=0; i < value_size; i++) { + res1[i] = number(res0[i]); + } + jbyteArray jres = env->NewByteArray((jsize)value_size); + env->SetByteArrayRegion(jres, 0, (jsize)value_size, (const jbyte *)res1); + java_exception_check_and_throw(env, E_FILE_LINE); + return jres; + } catch(...) { + rethrow_and_raise_java_exception(env); + } + return JNI_FALSE; +} + // // getter // @@ -742,7 +802,7 @@ void Java_direct_1bt_tinyb_DBTDevice_enablePairedNotificationsImpl(JNIEnv *env, // move BooleanDeviceCBContextRef into CaptureInvocationFunc and operator== includes javaCallback comparison FunctionDef<bool, std::shared_ptr<MgmtEvent>> funcDef = bindCaptureFunc(BooleanDeviceCBContextRef(ctx), nativeCallback); setObjectRef(env, obj, funcDef.cloneFunction(), "pairedNotificationRef"); // set java ref - // FIXME: Figure out paired:=true, as currently we only attach to unpaired + // Note that this is only called natively for unpaired, i.e. paired:=false. Using deviceConnected for paired:=true on Java side mgmt.addMgmtEventCallback(adapter.dev_id, MgmtEvent::Opcode::DEVICE_UNPAIRED, funcDef); } catch(...) { rethrow_and_raise_java_exception(env); diff --git a/java/org/tinyb/BluetoothDevice.java b/java/org/tinyb/BluetoothDevice.java index c4bc99ec..b0ba1420 100644 --- a/java/org/tinyb/BluetoothDevice.java +++ b/java/org/tinyb/BluetoothDevice.java @@ -177,13 +177,61 @@ public interface BluetoothDevice extends BluetoothObject */ boolean disconnectProfile(String arg_UUID) throws BluetoothException; - /** A connection to this device is established, and the device is then - * paired. - * @return TRUE if the device connected and paired - */ + /** + * A secure connection to this device is established, and the device is then paired. + * <p> + * Use {@link #pair(int[])} for direct_bt + * </p> + * @return TRUE if the device connected and paired + * @implNote secure pairing with JustWorks method on direct_bt.tinyb, + * but device must be {@link #connect(short, short, short, short, short, short)} before. + * Use {@link #pair(int[])} + */ boolean pair() throws BluetoothException; /** + * The device is securely paired with PasskeyEntry or JustWorks. + * <p> + * The device must be {@link #connect(short, short, short, short, short, short) connected} + * before pairing. + * </p> + * <p> + * If passkey is null or an empty string, JustWorks method is being used, otherwise PasskeyEntry. + * </p> + * @param passkey the optional secret used for secure PasskeyEntry method. + * Will be encrypted before sending to counterparty. + * Can be null or an empty string, in which case JustWork method is used. + * @return {@link HCIStatusCode#SUCCESS} if the command has been accepted, otherwise {@link HCIStatusCode} may disclose reason for rejection. + * @since 2.1.0 + * @implNote not implemented in tinyb.dbus + */ + HCIStatusCode pair(final String passkey) throws BluetoothException; + + /** + * Returns a vector of supported PairingMode by the device. + * <p> + * The device must be {@link #connect(short, short, short, short, short, short) connected} + * before querying this status. FIXME? + * </p> + * @return array of supported PairingMode, empty if pairing is not supported. + * @since 2.1.0 + * @implNote not implemented in tinyb.dbus + */ + PairingMode[] getSupportedPairingModes() throws BluetoothException; + + /** + * Returns a vector of required PairingMode by the device. + * <p> + * The device must be {@link #connect(short, short, short, short, short, short) connected} + * before querying this status. FIXME? + * </p> + * @return array of required PairingMode, empty if pairing is not required. + * @since 2.1.0 + * @implNote not implemented in tinyb.dbus + */ + PairingMode[] getRequiredPairingModes() throws BluetoothException; + + /** * Remove this device from the system (like an unpair). * <p> * Direct-BT: Disconnects this device via disconnect(..) and diff --git a/java/org/tinyb/PairingMode.java b/java/org/tinyb/PairingMode.java new file mode 100644 index 00000000..3f06d8e3 --- /dev/null +++ b/java/org/tinyb/PairingMode.java @@ -0,0 +1,85 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package org.tinyb; + +/** + * Bluetooth secure pairing mode + * <pre> + * BT Core Spec v5.2: Vol 1, Part A, 5 Security Overview + * BT Core Spec v5.2: Vol 1, Part A, 5.4 LE SECURITY + * </pre> + * <p> + * See {@link #get(int)} for its native integer mapping. + * </p> + * @since 2.1.0 + */ +public enum PairingMode { + /** No pairing mode, implying no secure connections, no encryption and no MITM protection. */ + NONE ((byte)0), + /** Just Works. Random key exchange with encryption but no MITM protection. */ + JUST_WORKS ((byte)1), + /** Passkey Entry. A known digit sequence (PIN) must be given as a secret to be validated on the device. Random key exchange with additional secret (PIN) and encryption and MITM protection. */ + PASSKEY_ENTRY ((byte)2), + /** Visual numeric comparison of digit sequence (PIN) shown on both devices, peripheral and host, to be answered. Random key exchange with additional secret (PIN) and encryption and MITM protection. */ + NUMERIC_COMPARISON ((byte)3), + /** Utilizing a second factor secret to be used as a secret, e.g. NFC field. Random key exchange with additional secret (2FA) and encryption and potential MITM protection. */ + OUT_OF_BAND ((byte)4); + + public final byte value; + + /** + * Maps the specified name to a constant of PairingMode. + * <p> + * Implementation simply returns {@link #valueOf(String)}. + * This maps the constant names itself to their respective constant. + * </p> + * @param name the string name to be mapped to a constant of this enum type. + * @return the corresponding constant of this enum type. + * @throws IllegalArgumentException if the specified name can't be mapped to a constant of this enum type + * as described above. + */ + public static PairingMode get(final String name) throws IllegalArgumentException { + return valueOf(name); + } + + /** + * Maps the specified integer value to a constant of {@link PairingMode}. + * @param value the integer value to be mapped to a constant of this enum type. + * @return the corresponding constant of this enum type, using {@link #NONE} if not supported. + */ + public static PairingMode get(final byte value) { + switch(value) { + case (byte) 0x01: return JUST_WORKS; + case (byte) 0x02: return PASSKEY_ENTRY; + case (byte) 0x03: return NUMERIC_COMPARISON; + case (byte) 0x04: return OUT_OF_BAND; + default: return NONE; + } + } + + PairingMode(final byte v) { + value = v; + } +} diff --git a/java/tinyb/dbus/DBusDevice.java b/java/tinyb/dbus/DBusDevice.java index bb24d0dd..7413ff18 100644 --- a/java/tinyb/dbus/DBusDevice.java +++ b/java/tinyb/dbus/DBusDevice.java @@ -43,6 +43,7 @@ import org.tinyb.BluetoothType; import org.tinyb.BluetoothUtils; import org.tinyb.GATTCharacteristicListener; import org.tinyb.HCIStatusCode; +import org.tinyb.PairingMode; public class DBusDevice extends DBusObject implements BluetoothDevice { @@ -105,7 +106,20 @@ public class DBusDevice extends DBusObject implements BluetoothDevice @Override public native boolean pair() throws BluetoothException; - @Override + @Override + public HCIStatusCode pair(final String passkey) throws BluetoothException { return HCIStatusCode.INTERNAL_FAILURE; } + + @Override + public final PairingMode[] getSupportedPairingModes() throws BluetoothException { + return new PairingMode[0]; + } + + @Override + public final PairingMode[] getRequiredPairingModes() throws BluetoothException { + return new PairingMode[0]; + } + + @Override public native boolean remove() throws BluetoothException; @Override diff --git a/src/direct_bt/BTTypes.cpp b/src/direct_bt/BTTypes.cpp index 6b39fa6a..5ed893f0 100644 --- a/src/direct_bt/BTTypes.cpp +++ b/src/direct_bt/BTTypes.cpp @@ -217,6 +217,33 @@ BTMode direct_bt::getBTMode(const std::string & value) noexcept { return BTMode::NONE; } +std::string direct_bt::getPairingModeString(const PairingMode v) noexcept { + switch(v) { + case PairingMode::NONE: return "NONE"; + case PairingMode::JUST_WORKS: return "JUST_WORKS"; + case PairingMode::PASSKEY_ENTRY: return "PASSKEY_ENTRY"; + case PairingMode::NUMERIC_COMPARISON: return "NUMERIC_COMPARISON"; + case PairingMode::OUT_OF_BAND: return "OUT_OF_BAND"; + } + return "Unknown PairingMode"; +} + +PairingMode direct_bt::getPairingMode(const std::string & value) noexcept { + if( "JUST_WORKS" == value ) { + return PairingMode::JUST_WORKS; + } + if( "PASSKEY_ENTRY" == value ) { + return PairingMode::PASSKEY_ENTRY; + } + if( "NUMERIC_COMPARISON" == value ) { + return PairingMode::NUMERIC_COMPARISON; + } + if( "OUT_OF_BAND" == value ) { + return PairingMode::OUT_OF_BAND; + } + return PairingMode::NONE; +} + ScanType direct_bt::getScanType(BTMode btMode) { switch ( btMode ) { case BTMode::DUAL: diff --git a/src/direct_bt/DBTDevice.cpp b/src/direct_bt/DBTDevice.cpp index d1df2d33..8ce50ed7 100644 --- a/src/direct_bt/DBTDevice.cpp +++ b/src/direct_bt/DBTDevice.cpp @@ -480,6 +480,21 @@ exit: return res; } +std::vector<PairingMode> DBTDevice::getSupportedPairingModes() { + std::vector<PairingMode> pairingModes; // FIXME: Implement LE Secure Connections + return pairingModes; +} + +std::vector<PairingMode> DBTDevice::getRequiredPairingModes() { + std::vector<PairingMode> pairingModes; // FIXME: Implement LE Secure Connections + return pairingModes; +} + +HCIStatusCode DBTDevice::pair(const std::string & passkey) { + (void) passkey; + return HCIStatusCode::INTERNAL_FAILURE; // FIXME: Implement LE Secure Connections +} + void DBTDevice::remove() { adapter.removeDevice(*this); } |