summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/bluetooth/ScoSocket.java6
-rw-r--r--core/jni/android_bluetooth_ScoSocket.cpp189
2 files changed, 187 insertions, 8 deletions
diff --git a/core/java/android/bluetooth/ScoSocket.java b/core/java/android/bluetooth/ScoSocket.java
index 116310a..b65a99a 100644
--- a/core/java/android/bluetooth/ScoSocket.java
+++ b/core/java/android/bluetooth/ScoSocket.java
@@ -86,14 +86,14 @@ public class ScoSocket {
/** Connect this SCO socket to the given BT address.
* Does not block.
*/
- public synchronized boolean connect(String address) {
+ public synchronized boolean connect(String address, String name) {
if (DBG) log("connect() " + this);
if (mState != STATE_READY) {
if (DBG) log("connect(): Bad state");
return false;
}
acquireWakeLock();
- if (connectNative(address)) {
+ if (connectNative(address, name)) {
mState = STATE_CONNECTING;
return true;
} else {
@@ -102,7 +102,7 @@ public class ScoSocket {
return false;
}
}
- private native boolean connectNative(String address);
+ private native boolean connectNative(String address, String name);
/** Accept incoming SCO connections.
* Does not block.
diff --git a/core/jni/android_bluetooth_ScoSocket.cpp b/core/jni/android_bluetooth_ScoSocket.cpp
index 3afe5f5..8588bc2 100644
--- a/core/jni/android_bluetooth_ScoSocket.cpp
+++ b/core/jni/android_bluetooth_ScoSocket.cpp
@@ -37,6 +37,23 @@
#ifdef HAVE_BLUETOOTH
#include <bluetooth/bluetooth.h>
#include <bluetooth/sco.h>
+#include <bluetooth/hci.h>
+
+#define MAX_LINE 255
+
+/*
+ * Defines the module strings used in the blacklist file.
+ * These are used by consumers of the blacklist file to see if the line is
+ * used by that module.
+ */
+#define SCO_BLACKLIST_MODULE_NAME "scoSocket"
+
+
+/* Define the type strings used in the blacklist file. */
+#define BLACKLIST_BY_NAME "name"
+#define BLACKLIST_BY_PARTIAL_NAME "partial_name"
+#define BLACKLIST_BY_OUI "vendor_oui"
+
#endif
/* Ideally, blocking I/O on a SCO socket would return when another thread
@@ -67,11 +84,28 @@ static jmethodID method_onClosed;
struct thread_data_t;
static void *work_thread(void *arg);
-static int connect_work(const char *address);
+static int connect_work(const char *address, uint16_t sco_pkt_type);
static int accept_work(int signal_sk);
static void wait_for_close(int sk, int signal_sk);
static void closeNative(JNIEnv *env, jobject object);
+static void parseBlacklist(void);
+static uint16_t getScoType(char *address, const char *name);
+
+#define COMPARE_STRING(key, s) (!strncmp(key, s, strlen(s)))
+
+/* Blacklist data */
+typedef struct scoBlacklist {
+ int fieldType;
+ char *value;
+ uint16_t scoType;
+ struct scoBlacklist *next;
+} scoBlacklist_t;
+
+#define BL_TYPE_NAME 1 // Field type is name string
+
+static scoBlacklist_t *blacklist = NULL;
+
/* shared native data - protected by mutex */
typedef struct {
pthread_mutex_t mutex;
@@ -87,11 +121,144 @@ struct thread_data_t {
bool is_accept; // accept (listening) or connect (outgoing) thread
int signal_sk; // socket for thread to listen for unblock signal
char address[BTADDR_SIZE]; // BT addres as string
+ uint16_t sco_pkt_type; // SCO packet types supported
};
static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
return (native_data_t *)(env->GetIntField(object, field_mNativeData));
}
+
+static uint16_t str2scoType (char *key) {
+ LOGV("%s: key = %s", __FUNCTION__, key);
+ if (COMPARE_STRING(key, "ESCO_HV1"))
+ return ESCO_HV1;
+ if (COMPARE_STRING(key, "ESCO_HV2"))
+ return ESCO_HV2;
+ if (COMPARE_STRING(key, "ESCO_HV3"))
+ return ESCO_HV3;
+ if (COMPARE_STRING(key, "ESCO_EV3"))
+ return ESCO_EV3;
+ if (COMPARE_STRING(key, "ESCO_EV4"))
+ return ESCO_EV4;
+ if (COMPARE_STRING(key, "ESCO_EV5"))
+ return ESCO_EV5;
+ if (COMPARE_STRING(key, "ESCO_2EV3"))
+ return ESCO_2EV3;
+ if (COMPARE_STRING(key, "ESCO_3EV3"))
+ return ESCO_3EV3;
+ if (COMPARE_STRING(key, "ESCO_2EV5"))
+ return ESCO_2EV5;
+ if (COMPARE_STRING(key, "ESCO_3EV5"))
+ return ESCO_3EV5;
+ if (COMPARE_STRING(key, "SCO_ESCO_MASK"))
+ return SCO_ESCO_MASK;
+ if (COMPARE_STRING(key, "EDR_ESCO_MASK"))
+ return EDR_ESCO_MASK;
+ if (COMPARE_STRING(key, "ALL_ESCO_MASK"))
+ return ALL_ESCO_MASK;
+ LOGE("Unknown SCO Type (%s) skipping",key);
+ return 0;
+}
+
+static void parseBlacklist(void) {
+ const char *filename = "/etc/bluetooth/blacklist.conf";
+ char line[MAX_LINE];
+ scoBlacklist_t *list = NULL;
+ scoBlacklist_t *newelem;
+
+ LOGV(__FUNCTION__);
+
+ /* Open file */
+ FILE *fp = fopen(filename, "r");
+ if(!fp) {
+ LOGE("Error(%s)opening blacklist file", strerror(errno));
+ return;
+ }
+
+ while (fgets(line, MAX_LINE, fp) != NULL) {
+ if ((COMPARE_STRING(line, "//")) || (!strcmp(line, "")))
+ continue;
+ char *module = strtok(line,":");
+ if (COMPARE_STRING(module, SCO_BLACKLIST_MODULE_NAME)) {
+ newelem = (scoBlacklist_t *)calloc(1, sizeof(scoBlacklist_t));
+ if (newelem == NULL) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return;
+ }
+ // parse line
+ char *type = strtok(NULL, ",");
+ char *valueList = strtok(NULL, ",");
+ char *paramList = strtok(NULL, ",");
+ if (COMPARE_STRING(type, BLACKLIST_BY_NAME)) {
+ // Extract Name from Value list
+ newelem->fieldType = BL_TYPE_NAME;
+ newelem->value = (char *)calloc(1, strlen(valueList));
+ if (newelem->value == NULL) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ continue;
+ }
+ valueList++; // Skip open quote
+ strncpy(newelem->value, valueList, strlen(valueList) - 1);
+
+ // Get Sco Settings from Parameters
+ char *param = strtok(paramList, ";");
+ uint16_t scoTypes = 0;
+ while (param != NULL) {
+ uint16_t sco;
+ if (param[0] == '-') {
+ param++;
+ sco = str2scoType(param);
+ if (sco != 0)
+ scoTypes &= ~sco;
+ } else if (param[0] == '+') {
+ param++;
+ sco = str2scoType(param);
+ if (sco != 0)
+ scoTypes |= sco;
+ } else if (param[0] == '=') {
+ param++;
+ sco = str2scoType(param);
+ if (sco != 0)
+ scoTypes = sco;
+ } else {
+ LOGE("Invalid SCO type must be =, + or -");
+ }
+ param = strtok(NULL, ";");
+ }
+ newelem->scoType = scoTypes;
+ } else {
+ LOGE("Unknown SCO type entry in Blacklist file");
+ continue;
+ }
+ if (list) {
+ list->next = newelem;
+ list = newelem;
+ } else {
+ blacklist = list = newelem;
+ }
+ LOGI("Entry name = %s ScoTypes = 0x%x", newelem->value,
+ newelem->scoType);
+ }
+ }
+ fclose(fp);
+ return;
+}
+static uint16_t getScoType(char *address, const char *name) {
+ uint16_t ret = 0;
+ scoBlacklist_t *list = blacklist;
+
+ while (list != NULL) {
+ if (list->fieldType == BL_TYPE_NAME) {
+ if (COMPARE_STRING(name, list->value)) {
+ ret = list->scoType;
+ break;
+ }
+ }
+ list = list->next;
+ }
+ LOGI("%s %s - 0x%x", __FUNCTION__, name, ret);
+ return ret;
+}
#endif
static void classInitNative(JNIEnv* env, jclass clazz) {
@@ -104,6 +271,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
method_onAccepted = env->GetMethodID(clazz, "onAccepted", "(I)V");
method_onConnected = env->GetMethodID(clazz, "onConnected", "(I)V");
method_onClosed = env->GetMethodID(clazz, "onClosed", "()V");
+
+ /* Read the blacklist file in here */
+ parseBlacklist();
#endif
}
@@ -192,7 +362,9 @@ static jboolean acceptNative(JNIEnv *env, jobject object) {
return JNI_FALSE;
}
-static jboolean connectNative(JNIEnv *env, jobject object, jstring address) {
+static jboolean connectNative(JNIEnv *env, jobject object, jstring address,
+ jstring name) {
+
LOGV(__FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
@@ -200,6 +372,7 @@ static jboolean connectNative(JNIEnv *env, jobject object, jstring address) {
pthread_t thread;
struct thread_data_t *data;
const char *c_address;
+ const char *c_name;
pthread_mutex_lock(&nat->mutex);
if (nat->signal_sk != -1) {
@@ -231,6 +404,11 @@ static jboolean connectNative(JNIEnv *env, jobject object, jstring address) {
env->ReleaseStringUTFChars(address, c_address);
data->is_accept = false;
+ c_name = env->GetStringUTFChars(name, NULL);
+ /* See if this device is in the black list */
+ data->sco_pkt_type = getScoType(data->address, c_name);
+ env->ReleaseStringUTFChars(name, c_name);
+
if (pthread_create(&thread, NULL, &work_thread, (void *)data) < 0) {
LOGE("%s: pthread_create() failed: %s", __FUNCTION__, strerror(errno));
return JNI_FALSE;
@@ -282,7 +460,7 @@ static void *work_thread(void *arg) {
sk = accept_work(data->signal_sk);
LOGV("SCO OBJECT %p END ACCEPT *****", data->nat->object);
} else {
- sk = connect_work(data->address);
+ sk = connect_work(data->address, data->sco_pkt_type);
}
/* callback with connection result */
@@ -426,7 +604,7 @@ error:
return -1;
}
-static int connect_work(const char *address) {
+static int connect_work(const char *address, uint16_t sco_pkt_type) {
LOGV(__FUNCTION__);
struct sockaddr_sco addr;
int sk = -1;
@@ -449,6 +627,7 @@ static int connect_work(const char *address) {
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
get_bdaddr(address, &addr.sco_bdaddr);
+ addr.sco_pkt_type = sco_pkt_type;
LOGI("Connecting to socket");
while (connect(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
if (errno != EINTR) {
@@ -493,7 +672,7 @@ static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void*)classInitNative},
{"initNative", "()V", (void *)initNative},
{"destroyNative", "()V", (void *)destroyNative},
- {"connectNative", "(Ljava/lang/String;)Z", (void *)connectNative},
+ {"connectNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)connectNative},
{"acceptNative", "()Z", (void *)acceptNative},
{"closeNative", "()V", (void *)closeNative},
};