2014-09-02 10:09:45

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 00/16] Move reconnect logic from HOG to GATT

Following patches moves reconnect feature from GATT clients to GATT.
GATT is in charge to decide if white list is used or legacy "passive scan"

There are also couple of fixes found in HOG during testing.

Tested on Android against kernel with mgmt version 1.6 and 1.7

Lukasz Rymanowski (16):
android/gatt: Fix for device type in gatt
android/hidhost: Remove invalid connecting state notification
android/hidhost: Allow to use cached dev when connecting
android/bluetooth: Add tracking if device is in white list
android/gatt: Add tracking for autoconnect apps
android/gatt: Add API to autoconnect GATT based devices
android/gatt: Add API to remove autoconnect GATT based device
android/gatt: Unsubscribe from autoconnect on unregister
android/gatt: Extract remove_autoconnect_device helper
android/gatt: Move find_conn up in the file
android/gatt: Notify apps interested in autoconnect about connection
android/gatt: Extract trigger le connection to new function
android/gatt: Move auto_connect_le() up in the file
android/gatt: Make sure GATT will reconnect after disconnection
android/gatt: Remove device from white list on device destroy
android/hidhost: Remove reconnect logic

android/bluetooth.c | 23 ++++-
android/gatt.c | 246 +++++++++++++++++++++++++++++++++++++++-------------
android/gatt.h | 2 +
android/hidhost.c | 38 +++-----
4 files changed, 218 insertions(+), 91 deletions(-)

--
1.8.4



2014-09-03 06:55:33

by Lukasz Rymanowski

[permalink] [raw]
Subject: Re: [PATCH 07/16] android/gatt: Add API to remove autoconnect GATT based device

Hi Szymon,

On 2 September 2014 17:27, Szymon Janc <[email protected]> wrote:
> Hi Łukasz,
>
> On Tuesday 02 of September 2014 12:09:52 Lukasz Rymanowski wrote:
>> ---
>> android/gatt.c | 23 +++++++++++++++++++++++
>> android/gatt.h | 1 +
>> 2 files changed, 24 insertions(+)
>>
>> diff --git a/android/gatt.c b/android/gatt.c
>> index 5d04ad8..0d0b56d 100644
>> --- a/android/gatt.c
>> +++ b/android/gatt.c
>> @@ -6755,3 +6755,26 @@ bool bt_gatt_add_autoconnect(unsigned int id, const bdaddr_t *addr)
>>
>> return true;
>> }
>> +
>> +void bt_gatt_remove_autoconnect(unsigned int id, const bdaddr_t *addr)
>> +{
>> + struct gatt_device *dev;
>> +
>> + DBG("");
>> +
>> + dev = find_device_by_addr(addr);
>> + if (!dev) {
>> + error("gatt: Device not found");
>> + return;
>> + }
>> +
>> + queue_remove(dev->autoconnect_apps, INT_TO_PTR(id));
>> +
>> + if (queue_isempty(dev->autoconnect_apps)) {
>> + bt_auto_connect_remove(addr);
>> + device_unref(dev);
>> +
>> + if (dev->state == DEVICE_CONNECT_INIT)
>> + device_set_state(dev, DEVICE_DISCONNECTED);
>
> This looks unclear to me since you are using dev after unref.

Yup, this is a bug - will be fixed.

> Shouldn't unref be done after you no longer need to use it? Otherwise
> things might crash due to use-after-free.
>
>> + }
>> +}
>> diff --git a/android/gatt.h b/android/gatt.h
>> index 40699b2..3382df9 100644
>> --- a/android/gatt.h
>> +++ b/android/gatt.h
>> @@ -40,3 +40,4 @@ bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr);
>> bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr);
>> bool bt_gatt_set_security(const bdaddr_t *bdaddr, int sec_level);
>> bool bt_gatt_add_autoconnect(unsigned int id, const bdaddr_t *addr);
>> +void bt_gatt_remove_autoconnect(unsigned int id, const bdaddr_t *addr);
>>
>
> --
> Best regards,
> Szymon Janc

Lukasz

2014-09-02 15:27:26

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 07/16] android/gatt: Add API to remove autoconnect GATT based device

Hi Łukasz,

On Tuesday 02 of September 2014 12:09:52 Lukasz Rymanowski wrote:
> ---
> android/gatt.c | 23 +++++++++++++++++++++++
> android/gatt.h | 1 +
> 2 files changed, 24 insertions(+)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index 5d04ad8..0d0b56d 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -6755,3 +6755,26 @@ bool bt_gatt_add_autoconnect(unsigned int id, const bdaddr_t *addr)
>
> return true;
> }
> +
> +void bt_gatt_remove_autoconnect(unsigned int id, const bdaddr_t *addr)
> +{
> + struct gatt_device *dev;
> +
> + DBG("");
> +
> + dev = find_device_by_addr(addr);
> + if (!dev) {
> + error("gatt: Device not found");
> + return;
> + }
> +
> + queue_remove(dev->autoconnect_apps, INT_TO_PTR(id));
> +
> + if (queue_isempty(dev->autoconnect_apps)) {
> + bt_auto_connect_remove(addr);
> + device_unref(dev);
> +
> + if (dev->state == DEVICE_CONNECT_INIT)
> + device_set_state(dev, DEVICE_DISCONNECTED);

This looks unclear to me since you are using dev after unref.
Shouldn't unref be done after you no longer need to use it? Otherwise
things might crash due to use-after-free.

> + }
> +}
> diff --git a/android/gatt.h b/android/gatt.h
> index 40699b2..3382df9 100644
> --- a/android/gatt.h
> +++ b/android/gatt.h
> @@ -40,3 +40,4 @@ bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr);
> bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr);
> bool bt_gatt_set_security(const bdaddr_t *bdaddr, int sec_level);
> bool bt_gatt_add_autoconnect(unsigned int id, const bdaddr_t *addr);
> +void bt_gatt_remove_autoconnect(unsigned int id, const bdaddr_t *addr);
>

--
Best regards,
Szymon Janc

2014-09-02 15:19:57

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 00/16] Move reconnect logic from HOG to GATT

Hi Łukasz,

On Tuesday 02 of September 2014 12:09:45 Lukasz Rymanowski wrote:
> Following patches moves reconnect feature from GATT clients to GATT.
> GATT is in charge to decide if white list is used or legacy "passive scan"
>
> There are also couple of fixes found in HOG during testing.
>
> Tested on Android against kernel with mgmt version 1.6 and 1.7
>
> Lukasz Rymanowski (16):
> android/gatt: Fix for device type in gatt
> android/hidhost: Remove invalid connecting state notification
> android/hidhost: Allow to use cached dev when connecting
> android/bluetooth: Add tracking if device is in white list
> android/gatt: Add tracking for autoconnect apps
> android/gatt: Add API to autoconnect GATT based devices
> android/gatt: Add API to remove autoconnect GATT based device
> android/gatt: Unsubscribe from autoconnect on unregister
> android/gatt: Extract remove_autoconnect_device helper
> android/gatt: Move find_conn up in the file
> android/gatt: Notify apps interested in autoconnect about connection
> android/gatt: Extract trigger le connection to new function
> android/gatt: Move auto_connect_le() up in the file
> android/gatt: Make sure GATT will reconnect after disconnection
> android/gatt: Remove device from white list on device destroy
> android/hidhost: Remove reconnect logic
>
> android/bluetooth.c | 23 ++++-
> android/gatt.c | 246 +++++++++++++++++++++++++++++++++++++++-------------
> android/gatt.h | 2 +
> android/hidhost.c | 38 +++-----
> 4 files changed, 218 insertions(+), 91 deletions(-)

Patches 1-6 and 10-13 are now applied. Thanks.

--
Best regards,
Szymon Janc

2014-09-02 10:10:01

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 16/16] android/hidhost: Remove reconnect logic

GATT can handle reconnect now, so lets remove that part of code from
here
---
android/hidhost.c | 23 ++++-------------------
1 file changed, 4 insertions(+), 19 deletions(-)

diff --git a/android/hidhost.c b/android/hidhost.c
index 3dc3c25..82cc32e 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -109,7 +109,6 @@ struct hid_device {
struct bt_uhid *uhid;
uint8_t last_hid_msg;
struct bt_hog *hog;
- guint reconnect_id;
int sec_level;
};

@@ -125,9 +124,6 @@ static void hid_device_free(void *data)
{
struct hid_device *dev = data;

- if (dev->reconnect_id > 0)
- g_source_remove(dev->reconnect_id);
-
if (dev->ctrl_watch > 0)
g_source_remove(dev->ctrl_watch);

@@ -768,19 +764,6 @@ fail:
hid_device_remove(dev);
}

-static gboolean hog_reconnect(void *user_data)
-{
- struct hid_device *dev = user_data;
-
- DBG("");
-
- dev->reconnect_id = 0;
-
- bt_gatt_connect_app(hog_app, &dev->dst);
-
- return FALSE;
-}
-
static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
{
GSList *l;
@@ -792,11 +775,10 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
if (err < 0) {
if (!dev)
return;
- if (dev->hog && !dev->reconnect_id) {
+ if (dev->hog) {
bt_hid_notify_state(dev,
HAL_HIDHOST_STATE_DISCONNECTED);
bt_hog_detach(dev->hog);
- dev->reconnect_id = g_idle_add(hog_reconnect, dev);
return;
}
goto fail;
@@ -829,6 +811,9 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)

bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTED);

+ if (!bt_gatt_add_autoconnect(hog_app, &dev->dst))
+ error("hidhost: Could not add to autoconnect list");
+
return;

fail:
--
1.8.4


2014-09-02 10:10:00

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 15/16] android/gatt: Remove device from white list on device destroy

---
android/gatt.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 8da6120..48bb936 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -722,6 +722,8 @@ static void destroy_device(void *data)
queue_destroy(dev->pending_requests, destroy_pending_request);
queue_destroy(dev->autoconnect_apps, NULL);

+ bt_auto_connect_remove(&dev->bdaddr);
+
free(dev);
}

--
1.8.4


2014-09-02 10:09:59

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 14/16] android/gatt: Make sure GATT will reconnect after disconnection

With this patch once remote is disconnected there is decision taken if
BfA should wait for reconnect or not.

Removing device from the autoconnect list has been removed from
connect_cb as it is now handled during disconnection
---
android/gatt.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 9b58644..8da6120 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -650,6 +650,13 @@ static void connection_cleanup(struct gatt_device *device)
queue_remove_all(device->services, NULL, NULL, destroy_service);

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

static void destroy_gatt_app(void *data)
@@ -1463,9 +1470,6 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)

device_set_state(dev, DEVICE_CONNECTED);

- if (queue_isempty(dev->autoconnect_apps))
- bt_auto_connect_remove(&dev->bdaddr);
-
/* Send exchange mtu request as we assume being client and server */
/* TODO: Dont exchange mtu if no client apps */
send_exchange_mtu_request(dev);
--
1.8.4


2014-09-02 10:09:58

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 13/16] android/gatt: Move auto_connect_le() up in the file

Move function up in the file. Will be needed by following patches.
---
android/gatt.c | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index c614e6a..9b58644 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -594,6 +594,23 @@ static void device_set_state(struct gatt_device *dev, uint32_t state)
dev->state = 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(&dev->bdaddr);
+
+ /* Trigger discovery if not already started */
+ if (!scanning) {
+ if (!bt_le_discovery_start()) {
+ error("gatt: Could not start scan");
+ return false;
+ }
+ }
+
+ return true;
+}
+
static void connection_cleanup(struct gatt_device *device)
{
if (device->watch_id) {
@@ -1825,23 +1842,6 @@ static int connect_bredr(struct gatt_device *dev)
return 0;
}

-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(&dev->bdaddr);
-
- /* Trigger discovery if not already started */
- if (!scanning) {
- if (!bt_le_discovery_start()) {
- error("gatt: Could not start scan");
- return false;
- }
- }
-
- return true;
-}
-
static bool trigger_connection(struct app_connection *connection)
{
bool ret;
--
1.8.4


2014-09-02 10:09:56

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 11/16] android/gatt: Notify apps interested in autoconnect about connection

This patch makes sure that application interested in auto connect for
particular devices, will be notified about new connections.
---
android/gatt.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index 2e978b9..94a65cb 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -1385,6 +1385,21 @@ static struct app_connection *find_conn(const bdaddr_t *addr, int32_t app_id)
&conn_match);
}

+static void create_app_connection(void *data, void *user_data)
+{
+ struct gatt_device *dev = user_data;
+ struct gatt_app *app;
+
+ app = find_app_by_id(PTR_TO_INT(data));
+ if (!app)
+ return;
+
+ DBG("Autoconnect application id=%d", app->id);
+
+ if (!find_conn(&dev->bdaddr, PTR_TO_INT(data)))
+ create_connection(dev, app);
+}
+
static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
{
struct gatt_device *dev = user_data;
@@ -1431,7 +1446,8 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)

device_set_state(dev, DEVICE_CONNECTED);

- bt_auto_connect_remove(&dev->bdaddr);
+ if (queue_isempty(dev->autoconnect_apps))
+ bt_auto_connect_remove(&dev->bdaddr);

/* Send exchange mtu request as we assume being client and server */
/* TODO: Dont exchange mtu if no client apps */
@@ -1456,6 +1472,12 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
status = GATT_SUCCESS;

reply:
+ /*
+ * Make sure there are app_connections for all apps interested in auto
+ * connect to that device
+ */
+ queue_foreach(dev->autoconnect_apps, create_app_connection, dev);
+
if (!dev->conn_cnt) {
struct app_connection *conn;

--
1.8.4


2014-09-02 10:09:57

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 12/16] android/gatt: Extract trigger le connection to new function

This will be needed in reconnect scenario
---
android/gatt.c | 41 ++++++++++++++++-------------------------
1 file changed, 16 insertions(+), 25 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 94a65cb..c614e6a 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -1825,15 +1825,19 @@ static int connect_bredr(struct gatt_device *dev)
return 0;
}

-static bool auto_connect(struct gatt_device *dev)
+static bool auto_connect_le(struct gatt_device *dev)
{
- bool err;
-
- err = bt_auto_connect_add(&dev->bdaddr);
- if (!err)
- return false;
+ /* For LE devices use auto connect feature if possible */
+ if (bt_kernel_conn_control())
+ return bt_auto_connect_add(&dev->bdaddr);

- device_set_state(dev, DEVICE_CONNECT_INIT);
+ /* Trigger discovery if not already started */
+ if (!scanning) {
+ if (!bt_le_discovery_start()) {
+ error("gatt: Could not start scan");
+ return false;
+ }
+ }

return true;
}
@@ -1852,24 +1856,11 @@ static bool trigger_connection(struct app_connection *connection)
BDADDR_BREDR)
return connect_bredr(connection->device) == 0;

- /*
- * For LE devices use auto connect feature if possible
- * Note: Connection state is handled inside auto_connect() func
- */
- if (bt_kernel_conn_control())
- return auto_connect(connection->device);
-
- /* Trigger discovery if not already started */
- if (!scanning) {
- if (!bt_le_discovery_start()) {
- error("gatt: Could not start scan");
- ret = false;
- break;
- }
- }
-
- ret = true;
- device_set_state(connection->device, DEVICE_CONNECT_INIT);
+ /* For LE use auto connect feature */
+ ret = auto_connect_le(connection->device);
+ if (ret)
+ device_set_state(connection->device,
+ DEVICE_CONNECT_INIT);
break;
case DEVICE_CONNECTED:
send_app_connect_notify(connection, GATT_SUCCESS);
--
1.8.4


2014-09-02 10:09:55

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 10/16] android/gatt: Move find_conn up in the file

---
android/gatt.c | 54 +++++++++++++++++++++++++++---------------------------
1 file changed, 27 insertions(+), 27 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 31a535c..2e978b9 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -1358,6 +1358,33 @@ static void send_app_connect_notifications(void *data, void *user_data)
send_app_connect_notify(conn, con_data->status);
}

+static struct app_connection *find_conn(const bdaddr_t *addr, int32_t app_id)
+{
+ struct app_connection conn_match;
+ struct gatt_device *dev = NULL;
+ struct gatt_app *app;
+
+ /* Check if app is registered */
+ app = find_app_by_id(app_id);
+ if (!app) {
+ error("gatt: Client id %d not found", app_id);
+ return NULL;
+ }
+
+ /* Check if device is known */
+ dev = find_device_by_addr(addr);
+ if (!dev) {
+ error("gatt: Client id %d not found", app_id);
+ return NULL;
+ }
+
+ conn_match.device = dev;
+ conn_match.app = app;
+
+ return queue_find(app_connections, match_connection_by_device_and_app,
+ &conn_match);
+}
+
static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
{
struct gatt_device *dev = user_data;
@@ -1902,33 +1929,6 @@ static void handle_client_unregister(const void *buf, uint16_t len)
HAL_OP_GATT_CLIENT_UNREGISTER, status);
}

-static struct app_connection *find_conn(const bdaddr_t *addr, int32_t app_id)
-{
- struct app_connection conn_match;
- struct gatt_device *dev = NULL;
- struct gatt_app *app;
-
- /* Check if app is registered */
- app = find_app_by_id(app_id);
- if (!app) {
- error("gatt: Client id %d not found", app_id);
- return NULL;
- }
-
- /* Check if device is known */
- dev = find_device_by_addr(addr);
- if (!dev) {
- error("gatt: Client id %d not found", app_id);
- return NULL;
- }
-
- conn_match.device = dev;
- conn_match.app = app;
-
- return queue_find(app_connections, match_connection_by_device_and_app,
- &conn_match);
-}
-
static uint8_t handle_connect(int32_t app_id, const bdaddr_t *addr)
{
struct app_connection conn_match;
--
1.8.4


2014-09-02 10:09:54

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 09/16] android/gatt: Extract remove_autoconnect_device helper

---
android/gatt.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index 348a2a2..31a535c 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -1837,6 +1837,15 @@ static bool trigger_connection(struct app_connection *connection)
return ret;
}

+static void remove_autoconnect_device(struct gatt_device *dev)
+{
+ bt_auto_connect_remove(&dev->bdaddr);
+ device_unref(dev);
+
+ if (dev->state == DEVICE_CONNECT_INIT)
+ device_set_state(dev, DEVICE_DISCONNECTED);
+}
+
static void clear_autoconnect_devices(int app_id)
{
struct gatt_device *dev;
@@ -1849,13 +1858,8 @@ static void clear_autoconnect_devices(int app_id)
while (dev) {
queue_remove(dev->autoconnect_apps, INT_TO_PTR(app_id));

- if (queue_isempty(dev->autoconnect_apps)) {
- bt_auto_connect_remove(&dev->bdaddr);
- device_unref(dev);
-
- if (dev->state == DEVICE_CONNECT_INIT)
- device_set_state(dev, DEVICE_DISCONNECTED);
- }
+ if (queue_isempty(dev->autoconnect_apps))
+ remove_autoconnect_device(dev);

dev = find_device_by_autoconnect_app_id(app_id);
};
@@ -6812,11 +6816,6 @@ void bt_gatt_remove_autoconnect(unsigned int id, const bdaddr_t *addr)

queue_remove(dev->autoconnect_apps, INT_TO_PTR(id));

- if (queue_isempty(dev->autoconnect_apps)) {
- bt_auto_connect_remove(addr);
- device_unref(dev);
-
- if (dev->state == DEVICE_CONNECT_INIT)
- device_set_state(dev, DEVICE_DISCONNECTED);
- }
+ if (queue_isempty(dev->autoconnect_apps))
+ remove_autoconnect_device(dev);
}
--
1.8.4


2014-09-02 10:09:53

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 08/16] android/gatt: Unsubscribe from autoconnect on unregister

When application does unregister, lets make sure that BfA does not keep
any auto connect devices for this app.
---
android/gatt.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 0d0b56d..348a2a2 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -370,6 +370,13 @@ static bool match_device_by_state(const void *data, const void *user_data)
return true;
}

+static bool match_device_by_ac_id(const void *data, const void *user_data)
+{
+ const struct gatt_device *dev = data;
+
+ return queue_find(dev->autoconnect_apps, match_by_value, user_data);
+}
+
static bool match_pending_device(const void *data, const void *user_data)
{
const struct gatt_device *dev = data;
@@ -442,6 +449,11 @@ static struct gatt_device *find_device_by_state(uint32_t state)
UINT_TO_PTR(state));
}

+static struct gatt_device *find_device_by_autoconnect_app_id(uint32_t id)
+{
+ return queue_find(gatt_devices, match_device_by_ac_id,
+ UINT_TO_PTR(id));
+}
static bool match_srvc_by_element_id(const void *data, const void *user_data)
{
const struct element_id *exp_id = user_data;
@@ -1825,10 +1837,40 @@ static bool trigger_connection(struct app_connection *connection)
return ret;
}

+static void clear_autoconnect_devices(int app_id)
+{
+ struct gatt_device *dev;
+
+ /*
+ * Check if application was registered for any devices to
+ * reconnect
+ */
+ dev = find_device_by_autoconnect_app_id(app_id);
+ while (dev) {
+ queue_remove(dev->autoconnect_apps, INT_TO_PTR(app_id));
+
+ if (queue_isempty(dev->autoconnect_apps)) {
+ bt_auto_connect_remove(&dev->bdaddr);
+ device_unref(dev);
+
+ if (dev->state == DEVICE_CONNECT_INIT)
+ device_set_state(dev, DEVICE_DISCONNECTED);
+ }
+
+ dev = find_device_by_autoconnect_app_id(app_id);
+ };
+}
+
static uint8_t unregister_app(int client_if)
{
struct gatt_app *cl;

+ /*
+ * Make sure that there is no devices in auto connect list for this
+ * application
+ */
+ clear_autoconnect_devices(client_if);
+
cl = queue_remove_if(gatt_apps, match_app_by_id, INT_TO_PTR(client_if));
if (!cl) {
error("gatt: client_if=%d not found", client_if);
--
1.8.4


2014-09-02 10:09:52

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 07/16] android/gatt: Add API to remove autoconnect GATT based device

---
android/gatt.c | 23 +++++++++++++++++++++++
android/gatt.h | 1 +
2 files changed, 24 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 5d04ad8..0d0b56d 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -6755,3 +6755,26 @@ bool bt_gatt_add_autoconnect(unsigned int id, const bdaddr_t *addr)

return true;
}
+
+void bt_gatt_remove_autoconnect(unsigned int id, const bdaddr_t *addr)
+{
+ struct gatt_device *dev;
+
+ DBG("");
+
+ dev = find_device_by_addr(addr);
+ if (!dev) {
+ error("gatt: Device not found");
+ return;
+ }
+
+ queue_remove(dev->autoconnect_apps, INT_TO_PTR(id));
+
+ if (queue_isempty(dev->autoconnect_apps)) {
+ bt_auto_connect_remove(addr);
+ device_unref(dev);
+
+ if (dev->state == DEVICE_CONNECT_INIT)
+ device_set_state(dev, DEVICE_DISCONNECTED);
+ }
+}
diff --git a/android/gatt.h b/android/gatt.h
index 40699b2..3382df9 100644
--- a/android/gatt.h
+++ b/android/gatt.h
@@ -40,3 +40,4 @@ bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr);
bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr);
bool bt_gatt_set_security(const bdaddr_t *bdaddr, int sec_level);
bool bt_gatt_add_autoconnect(unsigned int id, const bdaddr_t *addr);
+void bt_gatt_remove_autoconnect(unsigned int id, const bdaddr_t *addr);
--
1.8.4


2014-09-02 10:09:51

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 06/16] android/gatt: Add API to autoconnect GATT based devices

---
android/gatt.c | 30 ++++++++++++++++++++++++++++++
android/gatt.h | 1 +
2 files changed, 31 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index f526c16..5d04ad8 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -6725,3 +6725,33 @@ bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr)

return true;
}
+
+bool bt_gatt_add_autoconnect(unsigned int id, const bdaddr_t *addr)
+{
+ struct gatt_device *dev;
+ struct gatt_app *app;
+
+ DBG("");
+
+ app = find_app_by_id(id);
+ if (!app) {
+ error("gatt: App ID=%d not found", id);
+ return false;
+ }
+
+ dev = find_device_by_addr(addr);
+ if (!dev) {
+ error("gatt: Device not found");
+ return false;
+ }
+
+ /* Take reference of device for auto connect purpose */
+ if (queue_isempty(dev->autoconnect_apps))
+ device_ref(dev);
+
+ if (!queue_find(dev->autoconnect_apps, match_by_value,
+ INT_TO_PTR(id)))
+ return queue_push_head(dev->autoconnect_apps, INT_TO_PTR(id));
+
+ return true;
+}
diff --git a/android/gatt.h b/android/gatt.h
index 027dda3..40699b2 100644
--- a/android/gatt.h
+++ b/android/gatt.h
@@ -39,3 +39,4 @@ bool bt_gatt_unregister_app(unsigned int id);
bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr);
bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr);
bool bt_gatt_set_security(const bdaddr_t *bdaddr, int sec_level);
+bool bt_gatt_add_autoconnect(unsigned int id, const bdaddr_t *addr);
--
1.8.4


2014-09-02 10:09:50

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 05/16] android/gatt: Add tracking for autoconnect apps

Lets start to track which applications are interested in autoconnect
---
android/gatt.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index aea0a9f..f526c16 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -164,6 +164,8 @@ struct gatt_device {
int ref;
int conn_cnt;

+ struct queue *autoconnect_apps;
+
struct queue *pending_requests;
};

@@ -682,6 +684,7 @@ static void destroy_device(void *data)

queue_destroy(dev->services, destroy_service);
queue_destroy(dev->pending_requests, destroy_pending_request);
+ queue_destroy(dev->autoconnect_apps, NULL);

free(dev);
}
@@ -724,6 +727,12 @@ static struct gatt_device *create_device(const bdaddr_t *addr)
return NULL;
}

+ dev->autoconnect_apps = queue_new();
+ if (!dev->autoconnect_apps) {
+ error("gatt: Failed to allocate memory for client");
+ destroy_device(dev);
+ return NULL;
+ }

dev->pending_requests = queue_new();
if (!dev->pending_requests) {
--
1.8.4


2014-09-02 10:09:49

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 04/16] android/bluetooth: Add tracking if device is in white list

This patch adds tracking if device is in white list or not.
This is in order to make sure that we call mgmt inteface only when
neccessary
---
android/bluetooth.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 99e2aab..2f3a6d6 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -141,6 +141,8 @@ struct device {
bool le_paired;
bool le_bonded;

+ bool in_white_list;
+
char *name;
char *friendly_name;

@@ -1661,14 +1663,21 @@ bool bt_auto_connect_add(const bdaddr_t *addr)
return false;
}

+ if (dev->in_white_list) {
+ DBG("Device already in white list");
+ return true;
+ }
+
memset(&cp, 0, sizeof(cp));
bacpy(&cp.addr.bdaddr, addr);
cp.addr.type = dev->bdaddr_type;
cp.action = 0x02;

if (mgmt_send(mgmt_if, MGMT_OP_ADD_DEVICE, adapter.index, sizeof(cp),
- &cp, NULL, NULL, NULL) > 0)
+ &cp, NULL, NULL, NULL) > 0) {
+ dev->in_white_list = true;
return true;
+ }

error("Failed to add device");

@@ -1692,13 +1701,20 @@ void bt_auto_connect_remove(const bdaddr_t *addr)
return;
}

+ if (!dev->in_white_list) {
+ DBG("Device already removed from white list");
+ return;
+ }
+
memset(&cp, 0, sizeof(cp));
bacpy(&cp.addr.bdaddr, addr);
cp.addr.type = dev->bdaddr_type;

if (mgmt_send(mgmt_if, MGMT_OP_REMOVE_DEVICE, adapter.index,
- sizeof(cp), &cp, NULL, NULL, NULL) > 0)
+ sizeof(cp), &cp, NULL, NULL, NULL) > 0) {
+ dev->in_white_list = false;
return;
+ }

error("Failed to remove device");
}
@@ -2148,6 +2164,9 @@ static void mgmt_device_unpaired_event(uint16_t index, uint16_t length,

update_device_state(dev, ev->addr.type, HAL_STATUS_SUCCESS, false,
false, false);
+
+ /* Unpaired device is removed from the white list */
+ dev->in_white_list = false;
}

static void store_ltk(const bdaddr_t *dst, uint8_t bdaddr_type, bool master,
--
1.8.4


2014-09-02 10:09:47

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 02/16] android/hidhost: Remove invalid connecting state notification

HIDHOST_STATE_CONNECTING is reserved for local initiated connections
according to Android framework.
Sending it on incoming connection might confuse Android state machines.
---
android/hidhost.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/android/hidhost.c b/android/hidhost.c
index 476742e..652baa0 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -802,10 +802,8 @@ static void hog_conn_cb(const bdaddr_t *addr, int err, void *attrib)
goto fail;
}

- if (!dev) {
+ if (!dev)
dev = hid_device_new(addr);
- bt_hid_notify_state(dev, HAL_HIDHOST_STATE_CONNECTING);
- }

if (!dev->hog) {
/* TODO: Get device details and primary */
--
1.8.4


2014-09-02 10:09:48

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 03/16] android/hidhost: Allow to use cached dev when connecting

There is no reason to not allow connect when there is cached hid device
---
android/hidhost.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/android/hidhost.c b/android/hidhost.c
index 652baa0..3dc3c25 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -867,12 +867,13 @@ static void bt_hid_connect(const void *buf, uint16_t len)
android2bdaddr(&cmd->bdaddr, &dst);

l = g_slist_find_custom(devices, &dst, device_cmp);
- if (l) {
- status = HAL_STATUS_FAILED;
- goto failed;
- }
+ if (l)
+ dev = l->data;
+ else
+ dev = hid_device_new(&dst);

- dev = hid_device_new(&dst);
+ if (dev->state != HAL_HIDHOST_STATE_DISCONNECTED)
+ goto done;

ba2str(&dev->dst, addr);
DBG("connecting to %s", addr);
--
1.8.4


2014-09-02 10:09:46

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 01/16] android/gatt: Fix for device type in gatt

This patch fixes remote device type in GATT cache, which should be
updated on connect confirm
---
android/gatt.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/android/gatt.c b/android/gatt.c
index ae310f7..aea0a9f 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -6115,8 +6115,6 @@ static void connect_confirm(GIOChannel *io, void *user_data)
error("gatt: Could not create device");
goto drop;
}
-
- dev->bdaddr_type = dst_type;
} else {
if ((dev->state != DEVICE_DISCONNECTED) &&
!(dev->state == DEVICE_CONNECT_INIT &&
@@ -6130,6 +6128,8 @@ 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);
--
1.8.4