Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 408f333b authored by Eric Olsen's avatar Eric Olsen Committed by Android (Google) Code Review
Browse files

Merge "Add the blacklist for the SCO connections"

parents aac4bfb4 5e12aec1
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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.
+184 −5
Original line number Diff line number Diff line
@@ -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},
};