2015-03-05 11:57:44

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 1/3] android/gatt: Add support for direct connect

Don't use kernel auto connect if direct connect is requested by Android
Framework. This is required to be able to connect to non-bonded devices
that are using RPA.
---
android/gatt.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index e6b0753..638786d 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -1928,7 +1928,7 @@ static int connect_bredr(struct gatt_device *dev)
return 0;
}

-static bool trigger_connection(struct app_connection *conn)
+static bool trigger_connection(struct app_connection *conn, bool direct)
{
bool ret;

@@ -1942,8 +1942,11 @@ static bool trigger_connection(struct app_connection *conn)
BDADDR_BREDR)
return connect_bredr(conn->device) == 0;

- /* For LE use auto connect feature */
- ret = auto_connect_le(conn->device);
+ if (direct)
+ ret = connect_le(conn->device) == 0;
+ else
+ ret = auto_connect_le(conn->device);
+
if (ret)
device_set_state(conn->device, DEVICE_CONNECT_INIT);
break;
@@ -2103,7 +2106,7 @@ reply:
HAL_OP_GATT_CLIENT_UNREGISTER, status);
}

-static uint8_t handle_connect(int32_t app_id, const bdaddr_t *addr)
+static uint8_t handle_connect(int32_t app_id, const bdaddr_t *addr, bool direct)
{
struct app_connection conn_match;
struct app_connection *conn;
@@ -2134,7 +2137,7 @@ static uint8_t handle_connect(int32_t app_id, const bdaddr_t *addr)
return HAL_STATUS_NOMEM;
}

- if (!trigger_connection(conn))
+ if (!trigger_connection(conn, direct))
return HAL_STATUS_FAILED;

return HAL_STATUS_SUCCESS;
@@ -2146,15 +2149,13 @@ static void handle_client_connect(const void *buf, uint16_t len)
uint8_t status;
bdaddr_t addr;

- DBG("");
+ DBG("is_direct:%u transport:%u", cmd->is_direct, cmd->transport);

android2bdaddr(&cmd->bdaddr, &addr);

- /* TODO handle is_direct flag */
-
/* TODO handle transport flag */

- status = handle_connect(cmd->client_if, &addr);
+ status = handle_connect(cmd->client_if, &addr, cmd->is_direct);

ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_CONNECT,
status);
@@ -4211,7 +4212,7 @@ static void handle_client_test_command(const void *buf, uint16_t len)
break;
case GATT_CLIENT_TEST_CMD_CONNECT:
/* TODO u1 holds device type, for now assume BLE */
- status = handle_connect(test_client_if, &bdaddr);
+ status = handle_connect(test_client_if, &bdaddr, false);
break;
case GATT_CLIENT_TEST_CMD_DISCONNECT:
app = queue_find(gatt_apps, match_app_by_id,
@@ -4295,7 +4296,7 @@ static void handle_server_connect(const void *buf, uint16_t len)

/* TODO: Handle transport flag */

- status = handle_connect(cmd->server_if, &addr);
+ status = handle_connect(cmd->server_if, &addr, cmd->is_direct);

ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_SERVER_CONNECT,
status);
@@ -7350,7 +7351,7 @@ bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr)
{
uint8_t status;

- status = handle_connect(id, addr);
+ status = handle_connect(id, addr, false);

return status != HAL_STATUS_FAILED;
}
--
1.9.3



2015-03-05 15:59:30

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 1/3] android/gatt: Add support for direct connect

On Thursday 05 of March 2015 12:57:44 Szymon Janc wrote:
> Don't use kernel auto connect if direct connect is requested by Android
> Framework. This is required to be able to connect to non-bonded devices
> that are using RPA.
> ---
> android/gatt.c | 25 +++++++++++++------------
> 1 file changed, 13 insertions(+), 12 deletions(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index e6b0753..638786d 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -1928,7 +1928,7 @@ static int connect_bredr(struct gatt_device *dev)
> return 0;
> }
>
> -static bool trigger_connection(struct app_connection *conn)
> +static bool trigger_connection(struct app_connection *conn, bool direct)
> {
> bool ret;
>
> @@ -1942,8 +1942,11 @@ static bool trigger_connection(struct app_connection
> *conn) BDADDR_BREDR)
> return connect_bredr(conn->device) == 0;
>
> - /* For LE use auto connect feature */
> - ret = auto_connect_le(conn->device);
> + if (direct)
> + ret = connect_le(conn->device) == 0;
> + else
> + ret = auto_connect_le(conn->device);
> +
> if (ret)
> device_set_state(conn->device, DEVICE_CONNECT_INIT);
> break;
> @@ -2103,7 +2106,7 @@ reply:
> HAL_OP_GATT_CLIENT_UNREGISTER, status);
> }
>
> -static uint8_t handle_connect(int32_t app_id, const bdaddr_t *addr)
> +static uint8_t handle_connect(int32_t app_id, const bdaddr_t *addr, bool
> direct) {
> struct app_connection conn_match;
> struct app_connection *conn;
> @@ -2134,7 +2137,7 @@ static uint8_t handle_connect(int32_t app_id, const
> bdaddr_t *addr) return HAL_STATUS_NOMEM;
> }
>
> - if (!trigger_connection(conn))
> + if (!trigger_connection(conn, direct))
> return HAL_STATUS_FAILED;
>
> return HAL_STATUS_SUCCESS;
> @@ -2146,15 +2149,13 @@ static void handle_client_connect(const void *buf,
> uint16_t len) uint8_t status;
> bdaddr_t addr;
>
> - DBG("");
> + DBG("is_direct:%u transport:%u", cmd->is_direct, cmd->transport);
>
> android2bdaddr(&cmd->bdaddr, &addr);
>
> - /* TODO handle is_direct flag */
> -
> /* TODO handle transport flag */
>
> - status = handle_connect(cmd->client_if, &addr);
> + status = handle_connect(cmd->client_if, &addr, cmd->is_direct);
>
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_CONNECT,
> status);
> @@ -4211,7 +4212,7 @@ static void handle_client_test_command(const void
> *buf, uint16_t len) break;
> case GATT_CLIENT_TEST_CMD_CONNECT:
> /* TODO u1 holds device type, for now assume BLE */
> - status = handle_connect(test_client_if, &bdaddr);
> + status = handle_connect(test_client_if, &bdaddr, false);
> break;
> case GATT_CLIENT_TEST_CMD_DISCONNECT:
> app = queue_find(gatt_apps, match_app_by_id,
> @@ -4295,7 +4296,7 @@ static void handle_server_connect(const void *buf,
> uint16_t len)
>
> /* TODO: Handle transport flag */
>
> - status = handle_connect(cmd->server_if, &addr);
> + status = handle_connect(cmd->server_if, &addr, cmd->is_direct);
>
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_SERVER_CONNECT,
> status);
> @@ -7350,7 +7351,7 @@ bool bt_gatt_connect_app(unsigned int id, const
> bdaddr_t *addr) {
> uint8_t status;
>
> - status = handle_connect(id, addr);
> + status = handle_connect(id, addr, false);
>
> return status != HAL_STATUS_FAILED;
> }

Applied.

--
BR
Szymon Janc

2015-03-05 11:57:46

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 3/3] android/gatt: Handle device state in connect functions

Depending on kernel connection management support and type of
connection (direct or not) different states are expected after
connect. To make sure device state is correct set it connect
functions.
---
android/gatt.c | 42 ++++++++++++++++++------------------------
1 file changed, 18 insertions(+), 24 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 7263e31..9c2a280 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -573,6 +573,9 @@ static void device_set_state(struct gatt_device *dev, uint32_t state)
{
char bda[18];

+ if (dev->state == state)
+ return;
+
ba2str(&dev->bdaddr, bda);
DBG("gatt: Device %s state changed %s -> %s", bda,
device_state_str[dev->state], device_state_str[state]);
@@ -583,17 +586,18 @@ static void device_set_state(struct gatt_device *dev, uint32_t state)
static bool auto_connect_le(struct gatt_device *dev)
{
/* For LE devices use auto connect feature if possible */
- if (bt_kernel_conn_control())
- return bt_auto_connect_add(bt_get_id_addr(&dev->bdaddr, NULL));
-
- /* Trigger discovery if not already started */
- if (!scanning) {
- if (!bt_le_discovery_start()) {
+ if (bt_kernel_conn_control()) {
+ if (!bt_auto_connect_add(bt_get_id_addr(&dev->bdaddr, NULL)))
+ return false;
+ } else {
+ /* Trigger discovery if not already started */
+ if (!scanning && !bt_le_discovery_start()) {
error("gatt: Could not start scan");
return false;
}
}

+ device_set_state(dev, DEVICE_CONNECT_INIT);
return true;
}

@@ -640,12 +644,10 @@ static void connection_cleanup(struct gatt_device *device)

device_set_state(device, DEVICE_DISCONNECTED);

- if (!queue_isempty(device->autoconnect_apps)) {
+ if (!queue_isempty(device->autoconnect_apps))
auto_connect_le(device);
- device_set_state(device, DEVICE_CONNECT_INIT);
- } else {
+ else
bt_auto_connect_remove(&device->bdaddr);
- }
}

static void destroy_gatt_app(void *data)
@@ -1649,6 +1651,8 @@ static int connect_le(struct gatt_device *dev)
/* Keep this, so we can cancel the connection */
dev->att_io = io;

+ device_set_state(dev, DEVICE_CONNECT_READY);
+
return 0;
}

@@ -1899,8 +1903,6 @@ static int connect_bredr(struct gatt_device *dev)

static bool trigger_connection(struct app_connection *conn, bool direct)
{
- bool ret;
-
switch (conn->device->state) {
case DEVICE_DISCONNECTED:
/*
@@ -1912,26 +1914,18 @@ static bool trigger_connection(struct app_connection *conn, bool direct)
return connect_bredr(conn->device) == 0;

if (direct)
- ret = connect_le(conn->device) == 0;
- else
- ret = auto_connect_le(conn->device);
+ return connect_le(conn->device) == 0;

- if (ret)
- device_set_state(conn->device, DEVICE_CONNECT_INIT);
- break;
+ return auto_connect_le(conn->device);
case DEVICE_CONNECTED:
notify_app_connect_status(conn, GATT_SUCCESS);
- ret = true;
- break;
+ return true;
case DEVICE_CONNECT_READY:
case DEVICE_CONNECT_INIT:
default:
/* In those cases connection is already triggered. */
- ret = true;
- break;
+ return true;
}
-
- return ret;
}

static void remove_autoconnect_device(struct gatt_device *dev)
--
1.9.3


2015-03-05 11:57:45

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 2/3] android/bluetooth: Remove address type from BT callbacks

GATT code should always use bt_get_id_addr() when directly dealing with
remote address. This is to make sure that proper address and type is
used.
---
android/bluetooth.c | 22 +++++++++----------
android/bluetooth.h | 11 +++++-----
android/gatt.c | 61 ++++++++---------------------------------------------
android/hidhost.c | 2 +-
4 files changed, 25 insertions(+), 71 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index e684d31..4d0cd48 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -887,7 +887,7 @@ static void send_paired_notification(void *data, void *user_data)
bt_paired_device_cb cb = data;
struct device *dev = user_data;

- cb(&dev->bdaddr, dev->bdaddr_type);
+ cb(&dev->bdaddr);
}

static void update_device_state(struct device *dev, uint8_t addr_type,
@@ -1946,8 +1946,7 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,

/* Notify Gatt if its registered for LE events */
if (bdaddr_type != BDADDR_BREDR && gatt_device_found_cb) {
- bdaddr_t *addr;
- uint8_t addr_type;
+ const bdaddr_t *addr;

/*
* If RPA is set it means that IRK was received and ID address
@@ -1955,16 +1954,13 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
* it needs to be used also in GATT notifications. Also GATT
* HAL implementation is using RPA for devices matching.
*/
- if (bacmp(&dev->rpa, BDADDR_ANY)) {
+ if (bacmp(&dev->rpa, BDADDR_ANY))
addr = &dev->rpa;
- addr_type = dev->rpa_type;
- } else {
+ else
addr = &dev->bdaddr;
- addr_type = dev->bdaddr_type;
- }

- gatt_device_found_cb(addr, addr_type, rssi, data_len, data,
- connectable, dev->le_bonded);
+ gatt_device_found_cb(addr, rssi, data_len, data, connectable,
+ dev->le_bonded);
}

if (!dev->bredr_paired && !dev->le_paired)
@@ -4403,7 +4399,7 @@ static void send_unpaired_notification(void *data, void *user_data)
bt_unpaired_device_cb cb = data;
struct mgmt_addr_info *addr = user_data;

- cb(&addr->bdaddr, addr->type);
+ cb(&addr->bdaddr);
}

static void unpair_device_complete(uint8_t status, uint16_t length,
@@ -4425,7 +4421,9 @@ static void unpair_device_complete(uint8_t status, uint16_t length,
false, false);

/* Cast rp->addr to (void *) since queue_foreach don't take const */
- queue_foreach(unpaired_cb_list, send_unpaired_notification,
+
+ if (!dev->le_paired && !dev->bredr_paired)
+ queue_foreach(unpaired_cb_list, send_unpaired_notification,
(void *)&rp->addr);
}

diff --git a/android/bluetooth.h b/android/bluetooth.h
index 8b8a1f0..4b17209 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -35,10 +35,9 @@ void bt_bluetooth_unregister(void);
int bt_adapter_add_record(sdp_record_t *rec, uint8_t svc_hint);
void bt_adapter_remove_record(uint32_t handle);

-typedef void (*bt_le_device_found)(const bdaddr_t *addr, uint8_t addr_type,
- int rssi, uint16_t eir_len,
- const void *eir, bool connectable,
- bool bonded);
+typedef void (*bt_le_device_found)(const bdaddr_t *addr, int rssi,
+ uint16_t eir_len, const void *eir,
+ bool connectable, bool bonded);
bool bt_le_register(bt_le_device_found cb);
void bt_le_unregister(void);

@@ -81,11 +80,11 @@ bool bt_auto_connect_add(const bdaddr_t *addr);

void bt_auto_connect_remove(const bdaddr_t *addr);

-typedef void (*bt_unpaired_device_cb)(const bdaddr_t *addr, uint8_t type);
+typedef void (*bt_unpaired_device_cb)(const bdaddr_t *addr);
bool bt_unpaired_register(bt_unpaired_device_cb cb);
void bt_unpaired_unregister(bt_unpaired_device_cb cb);

-typedef void (*bt_paired_device_cb)(const bdaddr_t *addr, uint8_t type);
+typedef void (*bt_paired_device_cb)(const bdaddr_t *addr);
bool bt_paired_register(bt_paired_device_cb cb);
void bt_paired_unregister(bt_paired_device_cb cb);
bool bt_is_pairing(const bdaddr_t *addr);
diff --git a/android/gatt.c b/android/gatt.c
index 638786d..7263e31 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -153,7 +153,6 @@ struct notification_data {

struct gatt_device {
bdaddr_t bdaddr;
- uint8_t bdaddr_type;

gatt_device_state_t state;

@@ -584,24 +583,8 @@ static void device_set_state(struct gatt_device *dev, uint32_t state)
static bool auto_connect_le(struct gatt_device *dev)
{
/* For LE devices use auto connect feature if possible */
- if (bt_kernel_conn_control()) {
- const bdaddr_t *bdaddr;
-
- /*
- * If address type is random it might be that IRK was received
- * and random is just for faking Android Framework. ID address
- * should be used for connection if present.
- */
- if (dev->bdaddr_type == BDADDR_LE_RANDOM) {
- bdaddr = bt_get_id_addr(&dev->bdaddr, NULL);
- if (!bdaddr)
- return -EINVAL;
- } else {
- bdaddr = &dev->bdaddr;
- }
-
- return bt_auto_connect_add(bdaddr);
- }
+ if (bt_kernel_conn_control())
+ return bt_auto_connect_add(bt_get_id_addr(&dev->bdaddr, NULL));

/* Trigger discovery if not already started */
if (!scanning) {
@@ -1642,19 +1625,7 @@ static int connect_le(struct gatt_device *dev)

DBG("Connection attempt to: %s", addr);

- /*
- * If address type is random it might be that IRK was received and
- * random is just for faking Android Framework. ID address should be
- * used for connection if present.
- */
- if (dev->bdaddr_type == BDADDR_LE_RANDOM) {
- bdaddr = bt_get_id_addr(&dev->bdaddr, &bdaddr_type);
- if (!bdaddr)
- return -EINVAL;
- } else {
- bdaddr = &dev->bdaddr;
- bdaddr_type = dev->bdaddr_type;
- }
+ bdaddr = bt_get_id_addr(&dev->bdaddr, &bdaddr_type);

/*
* This connection will help us catch any PDUs that comes before
@@ -1703,10 +1674,9 @@ static void bt_le_discovery_stop_cb(void)
bt_le_discovery_start();
}

-static void le_device_found_handler(const bdaddr_t *addr, uint8_t addr_type,
- int rssi, uint16_t eir_len,
- const void *eir,
- bool connectable, bool bonded)
+static void le_device_found_handler(const bdaddr_t *addr, int rssi,
+ uint16_t eir_len, const void *eir,
+ bool connectable, bool bonded)
{
uint8_t buf[IPC_MTU];
struct hal_ev_gatt_client_scan_result *ev = (void *) buf;
@@ -1749,7 +1719,6 @@ done:
return;

device_set_state(dev, DEVICE_CONNECT_READY);
- dev->bdaddr_type = addr_type;

/*
* We are ok to perform connect now. Stop discovery
@@ -6717,16 +6686,12 @@ done:
static void connect_confirm(GIOChannel *io, void *user_data)
{
struct gatt_device *dev;
- uint8_t dst_type;
bdaddr_t dst;
GError *gerr = NULL;

DBG("");

- bt_io_get(io, &gerr,
- BT_IO_OPT_DEST_BDADDR, &dst,
- BT_IO_OPT_DEST_TYPE, &dst_type,
- BT_IO_OPT_INVALID);
+ bt_io_get(io, &gerr, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID);
if (gerr) {
error("gatt: bt_io_get: %s", gerr->message);
g_error_free(gerr);
@@ -6754,8 +6719,6 @@ static void connect_confirm(GIOChannel *io, void *user_data)
}
}

- dev->bdaddr_type = dst_type;
-
if (!bt_io_accept(io, connect_cb, device_ref(dev), NULL, NULL)) {
error("gatt: failed to accept connection");
device_unref(dev);
@@ -7120,7 +7083,7 @@ static bool start_listening(void)
return true;
}

-static void gatt_paired_cb(const bdaddr_t *addr, uint8_t type)
+static void gatt_paired_cb(const bdaddr_t *addr)
{
struct gatt_device *dev;
char address[18];
@@ -7130,9 +7093,6 @@ static void gatt_paired_cb(const bdaddr_t *addr, uint8_t type)
if (!dev)
return;

- if (dev->bdaddr_type != type)
- return;
-
ba2str(addr, address);
DBG("Paired device %s", address);

@@ -7149,7 +7109,7 @@ static void gatt_paired_cb(const bdaddr_t *addr, uint8_t type)
search_dev_for_srvc(conn, NULL);
}

-static void gatt_unpaired_cb(const bdaddr_t *addr, uint8_t type)
+static void gatt_unpaired_cb(const bdaddr_t *addr)
{
struct gatt_device *dev;
char address[18];
@@ -7158,9 +7118,6 @@ static void gatt_unpaired_cb(const bdaddr_t *addr, uint8_t type)
if (!dev)
return;

- if (dev->bdaddr_type != type)
- return;
-
ba2str(addr, address);
DBG("Unpaired device %s", address);

diff --git a/android/hidhost.c b/android/hidhost.c
index b696563..2e589f4 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -1495,7 +1495,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
}
}

-static void hid_unpaired_cb(const bdaddr_t *addr, uint8_t type)
+static void hid_unpaired_cb(const bdaddr_t *addr)
{
GSList *l;
struct hid_device *dev;
--
1.9.3