diff options
author | Jaikumar Ganesh <jaikumar@google.com> | 2010-09-09 15:37:57 -0700 |
---|---|---|
committer | Jaikumar Ganesh <jaikumar@google.com> | 2010-09-13 11:40:21 -0700 |
commit | cc5494c9996f809e36539b24e8b6b67683383d29 (patch) | |
tree | 5d4109c77cc1696d4665659a17b4458062fd7d0c | |
parent | fbd2646705c52c111f041b16d7cb34cb922a2a64 (diff) | |
download | frameworks_base-cc5494c9996f809e36539b24e8b6b67683383d29.zip frameworks_base-cc5494c9996f809e36539b24e8b6b67683383d29.tar.gz frameworks_base-cc5494c9996f809e36539b24e8b6b67683383d29.tar.bz2 |
Out Of Band API for Secure Simple Pairing.
Change-Id: I54ded27ab85d46eef3d2cca84f2394b1ffe88ced
-rw-r--r-- | core/java/android/bluetooth/BluetoothAdapter.java | 33 | ||||
-rw-r--r-- | core/java/android/bluetooth/BluetoothDevice.java | 58 | ||||
-rw-r--r-- | core/java/android/bluetooth/IBluetooth.aidl | 4 | ||||
-rw-r--r-- | core/java/android/server/BluetoothEventLoop.java | 27 | ||||
-rw-r--r-- | core/java/android/server/BluetoothService.java | 90 | ||||
-rw-r--r-- | core/jni/android_server_BluetoothEventLoop.cpp | 60 | ||||
-rw-r--r-- | core/jni/android_server_BluetoothService.cpp | 113 |
7 files changed, 381 insertions, 4 deletions
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 03bcadc..16a8c57 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -26,8 +26,10 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import android.util.Pair; import java.io.IOException; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; @@ -863,6 +865,37 @@ public final class BluetoothAdapter { return socket; } + /** + * Read the local Out of Band Pairing Data + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} + * + * @return Pair<byte[], byte[]> of Hash and Randomizer + * + * @hide + */ + public Pair<byte[], byte[]> readOutOfBandData() { + if (getState() != STATE_ON) return null; + try { + byte[] hash = new byte[16]; + byte[] randomizer = new byte[16]; + + byte[] ret = mService.readOutOfBandData(); + + if (ret == null || ret.length != 32) return null; + + hash = Arrays.copyOfRange(ret, 0, 16); + randomizer = Arrays.copyOfRange(ret, 16, 32); + + if (DBG) { + Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) + + ":" + Arrays.toString(randomizer)); + } + return new Pair<byte[], byte[]>(hash, randomizer); + + } catch (RemoteException e) {Log.e(TAG, "", e);} + return null; + } + private Set<BluetoothDevice> toDeviceSet(String[] addresses) { Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length); for (int i = 0; i < addresses.length; i++) { diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index e77e76f..e577ec4 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -325,7 +325,9 @@ public final class BluetoothDevice implements Parcelable { /** The user will be prompted to enter the passkey displayed on remote device * @hide */ public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4; - + /** The user will be prompted to accept or deny the OOB pairing request + * @hide */ + public static final int PAIRING_VARIANT_OOB_CONSENT = 5; /** * Used as an extra field in {@link #ACTION_UUID} intents, * Contains the {@link android.os.ParcelUuid}s of the remote device which @@ -464,6 +466,52 @@ public final class BluetoothDevice implements Parcelable { } /** + * Start the bonding (pairing) process with the remote device using the + * Out Of Band mechanism. + * + * <p>This is an asynchronous call, it will return immediately. Register + * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when + * the bonding process completes, and its result. + * + * <p>Android system services will handle the necessary user interactions + * to confirm and complete the bonding process. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. + * + * @param hash - Simple Secure pairing hash + * @param randomizer - The random key obtained using OOB + * @return false on immediate error, true if bonding will begin + * + * @hide + */ + public boolean createBondOutOfBand(byte[] hash, byte[] randomizer) { + try { + return sService.createBondOutOfBand(mAddress, hash, randomizer); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** + * Set the Out Of Band data for a remote device to be used later + * in the pairing mechanism. Users can obtain this data through other + * trusted channels + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. + * + * @param hash Simple Secure pairing hash + * @param randomizer The random key obtained using OOB + * @return false on error; true otherwise + * + * @hide + */ + public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) { + try { + return sService.setDeviceOutOfBandData(mAddress, hash, randomizer); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** * Cancel an in-progress bonding request started with {@link #createBond}. * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. * @@ -617,6 +665,14 @@ public final class BluetoothDevice implements Parcelable { } /** @hide */ + public boolean setRemoteOutOfBandData() { + try { + return sService.setRemoteOutOfBandData(mAddress); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** @hide */ public boolean cancelPairingUserInput() { try { return sService.cancelPairingUserInput(mAddress); diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index ea71034..6dd8dd6 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -44,12 +44,15 @@ interface IBluetooth boolean startDiscovery(); boolean cancelDiscovery(); boolean isDiscovering(); + byte[] readOutOfBandData(); boolean createBond(in String address); + boolean createBondOutOfBand(in String address, in byte[] hash, in byte[] randomizer); boolean cancelBondProcess(in String address); boolean removeBond(in String address); String[] listBonds(); int getBondState(in String address); + boolean setDeviceOutOfBandData(in String address, in byte[] hash, in byte[] randomizer); String getRemoteName(in String address); int getRemoteClass(in String address); @@ -60,6 +63,7 @@ interface IBluetooth boolean setPin(in String address, in byte[] pin); boolean setPasskey(in String address, int passkey); boolean setPairingConfirmation(in String address, boolean confirm); + boolean setRemoteOutOfBandData(in String addres); boolean cancelPairingUserInput(in String address); boolean setTrust(in String address, in boolean value); diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 094258b..9b28a9a 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -551,6 +551,17 @@ class BluetoothEventLoop { mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); } + private void onRequestOobData(String objectPath , int nativeData) { + String address = checkPairingRequestAndGetAddress(objectPath, nativeData); + if (address == null) return; + + Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); + intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, + BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT); + mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); + } + private boolean onAgentAuthorize(String objectPath, String deviceUuid) { String address = mBluetoothService.getAddressFromObjectPath(objectPath); if (address == null) { @@ -583,7 +594,21 @@ class BluetoothEventLoop { return authorized; } - boolean isOtherSinkInNonDisconnectingState(String address) { + private boolean onAgentOutOfBandDataAvailable(String objectPath) { + if (!mBluetoothService.isEnabled()) return false; + + String address = mBluetoothService.getAddressFromObjectPath(objectPath); + if (address == null) return false; + + if (mBluetoothService.getDeviceOutOfBandData( + mAdapter.getRemoteDevice(address)) != null) { + return true; + } + return false; + + } + + private boolean isOtherSinkInNonDisconnectingState(String address) { BluetoothA2dp a2dp = new BluetoothA2dp(mContext); Set<BluetoothDevice> devices = a2dp.getNonDisconnectedSinks(); if (devices.size() == 0) return false; diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index b2aa04d..d53ac80 100644 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -50,6 +50,7 @@ import android.os.ServiceManager; import android.os.SystemService; import android.provider.Settings; import android.util.Log; +import android.util.Pair; import com.android.internal.app.IBatteryStats; @@ -129,6 +130,8 @@ public class BluetoothService extends IBluetooth.Stub { private final BluetoothProfileState mHfpProfileState; private BluetoothA2dpService mA2dpService; + private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData; + private static String mDockAddress; private String mDockPin; @@ -183,6 +186,7 @@ public class BluetoothService extends IBluetooth.Stub { mDeviceProperties = new HashMap<String, Map<String,String>>(); mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>(); + mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>(); mUuidIntentTracker = new ArrayList<String>(); mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>(); mServiceRecordToPid = new HashMap<Integer, Integer>(); @@ -1119,7 +1123,7 @@ public class BluetoothService extends IBluetooth.Stub { mIsDiscovering = isDiscovering; } - public synchronized boolean createBond(String address) { + private boolean isBondingFeasible(String address) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (!isEnabledInternal()) return false; @@ -1149,8 +1153,13 @@ public class BluetoothService extends IBluetooth.Stub { return false; } } + return true; + } - if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) { + public synchronized boolean createBond(String address) { + if (!isBondingFeasible(address)) return false; + + if (!createPairedDeviceNative(address, 60000 /*1 minute*/ )) { return false; } @@ -1160,6 +1169,51 @@ public class BluetoothService extends IBluetooth.Stub { return true; } + public synchronized boolean createBondOutOfBand(String address, byte[] hash, + byte[] randomizer) { + if (!isBondingFeasible(address)) return false; + + if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) { + return false; + } + + setDeviceOutOfBandData(address, hash, randomizer); + mBondState.setPendingOutgoingBonding(address); + mBondState.setBondState(address, BluetoothDevice.BOND_BONDING); + + return true; + } + + public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash, + byte[] randomizer) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); + if (!isEnabledInternal()) return false; + + Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer); + + if (DBG) { + log("Setting out of band data for:" + address + ":" + + Arrays.toString(hash) + ":" + Arrays.toString(randomizer)); + } + + mDeviceOobData.put(address, value); + return true; + } + + Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) { + return mDeviceOobData.get(device.getAddress()); + } + + + public synchronized byte[] readOutOfBandData() { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, + "Need BLUETOOTH permission"); + if (!isEnabledInternal()) return null; + + return readAdapterOutOfBandDataNative(); + } + public synchronized boolean cancelBondProcess(String address) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); @@ -1551,6 +1605,32 @@ public class BluetoothService extends IBluetooth.Stub { return setPairingConfirmationNative(address, confirm, data.intValue()); } + public synchronized boolean setRemoteOutOfBandData(String address) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); + if (!isEnabledInternal()) return false; + address = address.toUpperCase(); + Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address); + if (data == null) { + Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " + + "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" + + " or by bluez.\n"); + return false; + } + + Pair<byte[], byte[]> val = mDeviceOobData.get(address); + byte[] hash, randomizer; + if (val == null) { + // TODO: check what should be passed in this case. + hash = new byte[16]; + randomizer = new byte[16]; + } else { + hash = val.first; + randomizer = val.second; + } + return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue()); + } + public synchronized boolean cancelPairingUserInput(String address) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); @@ -2084,6 +2164,9 @@ public class BluetoothService extends IBluetooth.Stub { private native boolean stopDiscoveryNative(); private native boolean createPairedDeviceNative(String address, int timeout_ms); + private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms); + private native byte[] readAdapterOutOfBandDataNative(); + private native boolean cancelDeviceCreationNative(String address); private native boolean removeDeviceNative(String objectPath); private native int getDeviceServiceChannelNative(String objectPath, String uuid, @@ -2094,6 +2177,9 @@ public class BluetoothService extends IBluetooth.Stub { private native boolean setPasskeyNative(String address, int passkey, int nativeData); private native boolean setPairingConfirmationNative(String address, boolean confirm, int nativeData); + private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash, + byte[] randomizer, int nativeData); + private native boolean setDevicePropertyBooleanNative(String objectPath, String key, int value); private native boolean createDeviceNative(String address); diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index db45d6d..d8e049d 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -61,6 +61,8 @@ static jmethodID method_onRequestPasskey; static jmethodID method_onRequestPasskeyConfirmation; static jmethodID method_onRequestPairingConsent; static jmethodID method_onDisplayPasskey; +static jmethodID method_onRequestOobData; +static jmethodID method_onAgentOutOfBandDataAvailable; static jmethodID method_onAgentAuthorize; static jmethodID method_onAgentCancel; @@ -105,6 +107,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) { method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize", "(Ljava/lang/String;Ljava/lang/String;)Z"); + method_onAgentOutOfBandDataAvailable = env->GetMethodID(clazz, "onAgentOutOfBandDataAvailable", + "(Ljava/lang/String;)Z"); method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V"); method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode", "(Ljava/lang/String;I)V"); @@ -116,6 +120,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) { "(Ljava/lang/String;I)V"); method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey", "(Ljava/lang/String;II)V"); + method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData", + "(Ljava/lang/String;I)V"); field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I"); #endif @@ -305,6 +311,7 @@ static int register_agent(native_data_t *nat, { DBusMessage *msg, *reply; DBusError err; + bool oob = TRUE; if (!dbus_connection_register_object_path(nat->conn, agent_path, &agent_vtable, nat)) { @@ -326,6 +333,7 @@ static int register_agent(native_data_t *nat, } dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path, DBUS_TYPE_STRING, &capabilities, + DBUS_TYPE_BOOLEAN, &oob, DBUS_TYPE_INVALID); dbus_error_init(&err); @@ -934,6 +942,43 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, } goto success; } else if (dbus_message_is_method_call(msg, + "org.bluez.Agent", "OutOfBandAvailable")) { + char *object_path; + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_OBJECT_PATH, &object_path, + DBUS_TYPE_INVALID)) { + LOGE("%s: Invalid arguments for OutOfBandData available() method", __FUNCTION__); + goto failure; + } + + LOGV("... object_path = %s", object_path); + + bool available = + env->CallBooleanMethod(nat->me, method_onAgentOutOfBandDataAvailable, + env->NewStringUTF(object_path)); + + + // reply + if (available) { + DBusMessage *reply = dbus_message_new_method_return(msg); + if (!reply) { + LOGE("%s: Cannot create message reply\n", __FUNCTION__); + goto failure; + } + dbus_connection_send(nat->conn, reply, NULL); + dbus_message_unref(reply); + } else { + DBusMessage *reply = dbus_message_new_error(msg, + "org.bluez.Error.DoesNotExist", "OutofBand data not available"); + if (!reply) { + LOGE("%s: Cannot create message reply\n", __FUNCTION__); + goto failure; + } + dbus_connection_send(nat->conn, reply, NULL); + dbus_message_unref(reply); + } + goto success; + } else if (dbus_message_is_method_call(msg, "org.bluez.Agent", "RequestPinCode")) { char *object_path; if (!dbus_message_get_args(msg, NULL, @@ -964,6 +1009,21 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn, int(msg)); goto success; } else if (dbus_message_is_method_call(msg, + "org.bluez.Agent", "RequestOobData")) { + char *object_path; + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_OBJECT_PATH, &object_path, + DBUS_TYPE_INVALID)) { + LOGE("%s: Invalid arguments for RequestOobData() method", __FUNCTION__); + goto failure; + } + + dbus_message_ref(msg); // increment refcount because we pass to java + env->CallVoidMethod(nat->me, method_onRequestOobData, + env->NewStringUTF(object_path), + int(msg)); + goto success; + } else if (dbus_message_is_method_call(msg, "org.bluez.Agent", "DisplayPasskey")) { char *object_path; uint32_t passkey; diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp index 4420aca..daa59a6 100644 --- a/core/jni/android_server_BluetoothService.cpp +++ b/core/jni/android_server_BluetoothService.cpp @@ -288,6 +288,46 @@ done: #endif } +static jbyteArray readAdapterOutOfBandDataNative(JNIEnv *env, jobject object) { + LOGV(__FUNCTION__); +#ifdef HAVE_BLUETOOTH + native_data_t *nat = get_native_data(env, object); + DBusError err; + jbyte *hash, *randomizer; + jbyteArray byteArray = NULL; + int hash_len, r_len; + if (nat) { + DBusMessage *reply = dbus_func_args(env, nat->conn, + get_adapter_path(env, object), + DBUS_ADAPTER_IFACE, "ReadLocalOutOfBandData", + DBUS_TYPE_INVALID); + if (!reply) return NULL; + + dbus_error_init(&err); + if (dbus_message_get_args(reply, &err, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hash_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &r_len, + DBUS_TYPE_INVALID)) { + if (hash_len == 16 && r_len == 16) { + byteArray = env->NewByteArray(32); + if (byteArray) { + env->SetByteArrayRegion(byteArray, 0, 16, hash); + env->SetByteArrayRegion(byteArray, 16, 16, randomizer); + } + } else { + LOGE("readAdapterOutOfBandDataNative: Hash len = %d, R len = %d", + hash_len, r_len); + } + } else { + LOG_AND_FREE_DBUS_ERROR(&err); + } + dbus_message_unref(reply); + return byteArray; + } +#endif + return NULL; +} + static jboolean createPairedDeviceNative(JNIEnv *env, jobject object, jstring address, jint timeout_ms) { LOGV(__FUNCTION__); @@ -324,6 +364,41 @@ static jboolean createPairedDeviceNative(JNIEnv *env, jobject object, return JNI_FALSE; } +static jboolean createPairedDeviceOutOfBandNative(JNIEnv *env, jobject object, + jstring address, jint timeout_ms) { + LOGV(__FUNCTION__); +#ifdef HAVE_BLUETOOTH + native_data_t *nat = get_native_data(env, object); + jobject eventLoop = env->GetObjectField(object, field_mEventLoop); + struct event_loop_native_data_t *eventLoopNat = + get_EventLoop_native_data(env, eventLoop); + + if (nat && eventLoopNat) { + const char *c_address = env->GetStringUTFChars(address, NULL); + LOGV("... address = %s", c_address); + char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); + const char *capabilities = "DisplayYesNo"; + const char *agent_path = "/android/bluetooth/remote_device_agent"; + + strlcpy(context_address, c_address, BTADDR_SIZE); // for callback + bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms, + onCreatePairedDeviceResult, // callback + context_address, + eventLoopNat, + get_adapter_path(env, object), + DBUS_ADAPTER_IFACE, + "CreatePairedDeviceOutOfBand", + DBUS_TYPE_STRING, &c_address, + DBUS_TYPE_OBJECT_PATH, &agent_path, + DBUS_TYPE_STRING, &capabilities, + DBUS_TYPE_INVALID); + env->ReleaseStringUTFChars(address, c_address); + return ret ? JNI_TRUE : JNI_FALSE; + } +#endif + return JNI_FALSE; +} + static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object, jstring path, jstring pattern, jint attr_id) { @@ -490,6 +565,40 @@ static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address, return JNI_FALSE; } +static jboolean setRemoteOutOfBandDataNative(JNIEnv *env, jobject object, jstring address, + jbyteArray hash, jbyteArray randomizer, int nativeData) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + native_data_t *nat = get_native_data(env, object); + if (nat) { + DBusMessage *msg = (DBusMessage *)nativeData; + DBusMessage *reply = dbus_message_new_method_return(msg); + jbyte *h_ptr = env->GetByteArrayElements(hash, NULL); + jbyte *r_ptr = env->GetByteArrayElements(randomizer, NULL); + if (!reply) { + LOGE("%s: Cannot create message reply to return remote OOB data to " + "D-Bus\n", __FUNCTION__); + dbus_message_unref(msg); + return JNI_FALSE; + } + + dbus_message_append_args(reply, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &h_ptr, 16, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &r_ptr, 16, + DBUS_TYPE_INVALID); + + env->ReleaseByteArrayElements(hash, h_ptr, 0); + env->ReleaseByteArrayElements(randomizer, r_ptr, 0); + + dbus_connection_send(nat->conn, reply, NULL); + dbus_message_unref(msg); + dbus_message_unref(reply); + return JNI_TRUE; + } +#endif + return JNI_FALSE; +} + static jboolean setPinNative(JNIEnv *env, jobject object, jstring address, jstring pin, int nativeData) { #ifdef HAVE_BLUETOOTH @@ -907,7 +1016,10 @@ static JNINativeMethod sMethods[] = { {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative}, {"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative}, + {"readAdapterOutOfBandDataNative", "()[B", (void *)readAdapterOutOfBandDataNative}, {"createPairedDeviceNative", "(Ljava/lang/String;I)Z", (void *)createPairedDeviceNative}, + {"createPairedDeviceOutOfBandNative", "(Ljava/lang/String;I)Z", + (void *)createPairedDeviceOutOfBandNative}, {"cancelDeviceCreationNative", "(Ljava/lang/String;)Z", (void *)cancelDeviceCreationNative}, {"removeDeviceNative", "(Ljava/lang/String;)Z", (void *)removeDeviceNative}, {"getDeviceServiceChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)I", @@ -916,6 +1028,7 @@ static JNINativeMethod sMethods[] = { {"setPairingConfirmationNative", "(Ljava/lang/String;ZI)Z", (void *)setPairingConfirmationNative}, {"setPasskeyNative", "(Ljava/lang/String;II)Z", (void *)setPasskeyNative}, + {"setRemoteOutOfBandDataNative", "(Ljava/lang/String;[B[BI)Z", (void *)setRemoteOutOfBandDataNative}, {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative}, {"cancelPairingUserInputNative", "(Ljava/lang/String;I)Z", (void *)cancelPairingUserInputNative}, |