2014-08-28 08:37:19

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v2 0/3] Fix for handling unpaired devices

Following patches fix scenario when remote device is unpaired and
paired again. Issue found when testing HOG where basically after
re-pair HOG was not functional.

v2:
* bt_unpaired_register returns bool
* unpaired callback provides also bdaddr type



Lukasz Rymanowski (3):
android/bluetooth: Add unpaired device callback
android/hidhost: Add remove bond handling
android/gatt: Add remove bond handling

android/bluetooth.c | 45 ++++++++++++++++++++++++++++++++++++++++++---
android/bluetooth.h | 3 +++
android/gatt.c | 24 ++++++++++++++++++++++++
android/hidhost.c | 23 +++++++++++++++++++++++
4 files changed, 92 insertions(+), 3 deletions(-)

--
1.8.4



2014-08-28 20:54:09

by Lukasz Rymanowski

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] android/bluetooth: Add unpaired device callback

Hi Szymon,

On Thu, Aug 28, 2014 at 8:11 PM, Szymon Janc <[email protected]> wrote:
> Hi Łukasz,
>
> On Thursday 28 August 2014 10:37:20 Lukasz Rymanowski wrote:
>> GATT, HID, HOG, might be interested in the fact that some device has
>> been unpaired in order to clear cache or similar. This patch adds means
>> to register callback for unpaired event.
>> ---
>> android/bluetooth.c | 45 ++++++++++++++++++++++++++++++++++++++++++---
>> android/bluetooth.h | 3 +++
>> 2 files changed, 45 insertions(+), 3 deletions(-)
>>
>> diff --git a/android/bluetooth.c b/android/bluetooth.c
>> index 984ecba..e2a97a8 100644
>> --- a/android/bluetooth.c
>> +++ b/android/bluetooth.c
>> @@ -41,6 +41,7 @@
>> #include "lib/uuid.h"
>> #include "src/shared/util.h"
>> #include "src/shared/mgmt.h"
>> +#include "src/shared/queue.h"
>> #include "src/eir.h"
>> #include "lib/sdp.h"
>> #include "lib/sdp_lib.h"
>> @@ -223,6 +224,8 @@ static struct ipc *hal_ipc = NULL;
>>
>> static bool kernel_conn_control = false;
>>
>> +static struct queue *unpaired_cb_list;
>
> Should be explicitly initialized to NULL.

Will fix.
>
>> +
>> static void get_device_android_addr(struct device *dev, uint8_t *addr)
>> {
>> /*
>> @@ -1688,6 +1691,19 @@ void bt_auto_connect_remove(const bdaddr_t *addr)
>> error("Failed to remove device");
>> }
>>
>> +static bool match_by_value(const void *data, const void *user_data)
>> +{
>> + return data == user_data;
>> +}
>> +
>> +bool bt_unpaired_register(bt_unpaired_device_cb cb)
>> +{
>> + if (queue_find(unpaired_cb_list, match_by_value, cb))
>> + return false;
>> +
>> + return queue_push_head(unpaired_cb_list, cb);
>> +}
>> +
>> static bool rssi_above_threshold(int old, int new)
>> {
>> /* only 8 dBm or more */
>> @@ -4313,6 +4329,14 @@ failed:
>> status);
>> }
>>
>> +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);
>> +}
>> +
>> static void unpair_device_complete(uint8_t status, uint16_t length,
>> const void *param, void *user_data)
>> {
>> @@ -4330,6 +4354,9 @@ static void unpair_device_complete(uint8_t status,
>> uint16_t length,
>>
>> update_device_state(dev, rp->addr.type, HAL_STATUS_SUCCESS, false,
>> false, false);
>> +
>> + queue_foreach(unpaired_cb_list, send_unpaired_notification,
>> + (void *)&rp->addr);
>
> Is this (void *) cast needed?

Yes, because of queue api. Can put comment about that.
>
>> }
>>
>> static void handle_remove_bond_cmd(const void *buf, uint16_t len)
>> @@ -5114,6 +5141,12 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t
>> mode)
>>
>> DBG("mode 0x%x", mode);
>>
>> + unpaired_cb_list = queue_new();
>> + if (!unpaired_cb_list) {
>> + error("Can not allocate queue for unpaired callbacks");
>> + return false;
>> + }
>> +
>> missing_settings = adapter.current_settings ^
>> adapter.supported_settings;
>>
>> @@ -5129,7 +5162,7 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t
>> mode) /* Fail if controller does not support LE */
>> if (!(adapter.supported_settings & MGMT_SETTING_LE)) {
>> error("LE Mode not supported by controller");
>> - return false;
>> + goto failed;
>> }
>>
>> /* If LE it is not yet enabled then enable it */
>> @@ -5144,7 +5177,7 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t
>> mode) /* Fail if controller does not support BR/EDR */
>> if (!(adapter.supported_settings & MGMT_SETTING_BREDR)) {
>> error("BR/EDR Mode not supported");
>> - return false;
>> + goto failed;
>> }
>>
>> /* Enable BR/EDR if it is not enabled */
>> @@ -5162,7 +5195,7 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t
>> mode) break;
>> default:
>> error("Unknown mode 0x%x", mode);
>> - return false;
>> + goto failed;
>> }
>>
>> hal_ipc = ipc;
>> @@ -5171,6 +5204,10 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t
>> mode) G_N_ELEMENTS(cmd_handlers));
>>
>> return true;
>> +
>> +failed:
>> + queue_destroy(unpaired_cb_list, NULL);
>> + return false;
>> }
>>
>> void bt_bluetooth_unregister(void)
>> @@ -5185,4 +5222,6 @@ void bt_bluetooth_unregister(void)
>>
>> ipc_unregister(hal_ipc, HAL_SERVICE_ID_CORE);
>> hal_ipc = NULL;
>> +
>> + queue_destroy(unpaired_cb_list, NULL);
>> }
>> diff --git a/android/bluetooth.h b/android/bluetooth.h
>> index ac7f3ad..185477c 100644
>> --- a/android/bluetooth.h
>> +++ b/android/bluetooth.h
>> @@ -85,3 +85,6 @@ bool bt_kernel_conn_control(void);
>> 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);
>> +bool bt_unpaired_register(bt_unpaired_device_cb cb);
>
> Shouldn't we have an unregister function as well?

Well we could have it, but as you know in Android it will be useless.
Idea is that GATT and HID/HOG (and later maybe other) are registered
for that event all the time and in the end, the list of callbacks is
destroyed in bluetooth.c on BT unregister. Since all BT HALs lives as
long as BT is ON then this should be fine. BUt If you really need it I
can do it :)

>
> --
> Szymon K. Janc
> [email protected]
> --

\Łukasz

> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2014-08-28 18:11:34

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] android/bluetooth: Add unpaired device callback

Hi Łukasz,

On Thursday 28 August 2014 10:37:20 Lukasz Rymanowski wrote:
> GATT, HID, HOG, might be interested in the fact that some device has
> been unpaired in order to clear cache or similar. This patch adds means
> to register callback for unpaired event.
> ---
> android/bluetooth.c | 45 ++++++++++++++++++++++++++++++++++++++++++---
> android/bluetooth.h | 3 +++
> 2 files changed, 45 insertions(+), 3 deletions(-)
>
> diff --git a/android/bluetooth.c b/android/bluetooth.c
> index 984ecba..e2a97a8 100644
> --- a/android/bluetooth.c
> +++ b/android/bluetooth.c
> @@ -41,6 +41,7 @@
> #include "lib/uuid.h"
> #include "src/shared/util.h"
> #include "src/shared/mgmt.h"
> +#include "src/shared/queue.h"
> #include "src/eir.h"
> #include "lib/sdp.h"
> #include "lib/sdp_lib.h"
> @@ -223,6 +224,8 @@ static struct ipc *hal_ipc = NULL;
>
> static bool kernel_conn_control = false;
>
> +static struct queue *unpaired_cb_list;

Should be explicitly initialized to NULL.

> +
> static void get_device_android_addr(struct device *dev, uint8_t *addr)
> {
> /*
> @@ -1688,6 +1691,19 @@ void bt_auto_connect_remove(const bdaddr_t *addr)
> error("Failed to remove device");
> }
>
> +static bool match_by_value(const void *data, const void *user_data)
> +{
> + return data == user_data;
> +}
> +
> +bool bt_unpaired_register(bt_unpaired_device_cb cb)
> +{
> + if (queue_find(unpaired_cb_list, match_by_value, cb))
> + return false;
> +
> + return queue_push_head(unpaired_cb_list, cb);
> +}
> +
> static bool rssi_above_threshold(int old, int new)
> {
> /* only 8 dBm or more */
> @@ -4313,6 +4329,14 @@ failed:
> status);
> }
>
> +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);
> +}
> +
> static void unpair_device_complete(uint8_t status, uint16_t length,
> const void *param, void *user_data)
> {
> @@ -4330,6 +4354,9 @@ static void unpair_device_complete(uint8_t status,
> uint16_t length,
>
> update_device_state(dev, rp->addr.type, HAL_STATUS_SUCCESS, false,
> false, false);
> +
> + queue_foreach(unpaired_cb_list, send_unpaired_notification,
> + (void *)&rp->addr);

Is this (void *) cast needed?

> }
>
> static void handle_remove_bond_cmd(const void *buf, uint16_t len)
> @@ -5114,6 +5141,12 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t
> mode)
>
> DBG("mode 0x%x", mode);
>
> + unpaired_cb_list = queue_new();
> + if (!unpaired_cb_list) {
> + error("Can not allocate queue for unpaired callbacks");
> + return false;
> + }
> +
> missing_settings = adapter.current_settings ^
> adapter.supported_settings;
>
> @@ -5129,7 +5162,7 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t
> mode) /* Fail if controller does not support LE */
> if (!(adapter.supported_settings & MGMT_SETTING_LE)) {
> error("LE Mode not supported by controller");
> - return false;
> + goto failed;
> }
>
> /* If LE it is not yet enabled then enable it */
> @@ -5144,7 +5177,7 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t
> mode) /* Fail if controller does not support BR/EDR */
> if (!(adapter.supported_settings & MGMT_SETTING_BREDR)) {
> error("BR/EDR Mode not supported");
> - return false;
> + goto failed;
> }
>
> /* Enable BR/EDR if it is not enabled */
> @@ -5162,7 +5195,7 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t
> mode) break;
> default:
> error("Unknown mode 0x%x", mode);
> - return false;
> + goto failed;
> }
>
> hal_ipc = ipc;
> @@ -5171,6 +5204,10 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t
> mode) G_N_ELEMENTS(cmd_handlers));
>
> return true;
> +
> +failed:
> + queue_destroy(unpaired_cb_list, NULL);
> + return false;
> }
>
> void bt_bluetooth_unregister(void)
> @@ -5185,4 +5222,6 @@ void bt_bluetooth_unregister(void)
>
> ipc_unregister(hal_ipc, HAL_SERVICE_ID_CORE);
> hal_ipc = NULL;
> +
> + queue_destroy(unpaired_cb_list, NULL);
> }
> diff --git a/android/bluetooth.h b/android/bluetooth.h
> index ac7f3ad..185477c 100644
> --- a/android/bluetooth.h
> +++ b/android/bluetooth.h
> @@ -85,3 +85,6 @@ bool bt_kernel_conn_control(void);
> 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);
> +bool bt_unpaired_register(bt_unpaired_device_cb cb);

Shouldn't we have an unregister function as well?

--
Szymon K. Janc
[email protected]

2014-08-28 08:37:22

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v2 3/3] android/gatt: Add remove bond handling

With this patch GATT is aware about unpaired devices so the local cache
can be cleared
---
android/gatt.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 89748d2..b3c9c5c 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -6496,10 +6496,34 @@ static bool start_listening(void)
return true;
}

+static void gatt_unpaired_cb(const bdaddr_t *addr, uint8_t type)
+{
+ struct gatt_device *dev;
+ char address[18];
+
+ dev = find_device_by_addr(addr);
+ if (!dev)
+ return;
+
+ if (dev->bdaddr_type != type)
+ return;
+
+ ba2str(addr, address);
+ DBG("Unpaired device %s", address);
+
+ queue_remove(gatt_devices, dev);
+ destroy_device(dev);
+}
+
bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
{
DBG("");

+ if (!bt_unpaired_register(gatt_unpaired_cb)) {
+ error("gatt: Could not register unpaired callback");
+ return false;
+ }
+
if (!start_listening())
return false;

--
1.8.4


2014-08-28 08:37:21

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v2 2/3] android/hidhost: Add remove bond handling

With this patch HID/HOG is aware when remote device has been unpaired.
---
android/hidhost.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)

diff --git a/android/hidhost.c b/android/hidhost.c
index 5b31c95..c404088 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -1483,12 +1483,35 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
}
}

+static void hid_unpaired_cb(const bdaddr_t *addr, uint8_t type)
+{
+ GSList *l;
+ struct hid_device *dev;
+ char address[18];
+
+ l = g_slist_find_custom(devices, addr, device_cmp);
+ if (!l)
+ return;
+
+ dev = l->data;
+
+ ba2str(addr, address);
+ DBG("Unpaired device %s", address);
+
+ hid_device_remove(dev);
+}
+
bool bt_hid_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
{
GError *err = NULL;

DBG("");

+ if (!bt_unpaired_register(hid_unpaired_cb)) {
+ error("hidhost: Could not register unpaired callback");
+ return false;
+ }
+
bacpy(&adapter_addr, addr);

ctrl_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
--
1.8.4


2014-08-28 08:37:20

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v2 1/3] android/bluetooth: Add unpaired device callback

GATT, HID, HOG, might be interested in the fact that some device has
been unpaired in order to clear cache or similar. This patch adds means
to register callback for unpaired event.
---
android/bluetooth.c | 45 ++++++++++++++++++++++++++++++++++++++++++---
android/bluetooth.h | 3 +++
2 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 984ecba..e2a97a8 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -41,6 +41,7 @@
#include "lib/uuid.h"
#include "src/shared/util.h"
#include "src/shared/mgmt.h"
+#include "src/shared/queue.h"
#include "src/eir.h"
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
@@ -223,6 +224,8 @@ static struct ipc *hal_ipc = NULL;

static bool kernel_conn_control = false;

+static struct queue *unpaired_cb_list;
+
static void get_device_android_addr(struct device *dev, uint8_t *addr)
{
/*
@@ -1688,6 +1691,19 @@ void bt_auto_connect_remove(const bdaddr_t *addr)
error("Failed to remove device");
}

+static bool match_by_value(const void *data, const void *user_data)
+{
+ return data == user_data;
+}
+
+bool bt_unpaired_register(bt_unpaired_device_cb cb)
+{
+ if (queue_find(unpaired_cb_list, match_by_value, cb))
+ return false;
+
+ return queue_push_head(unpaired_cb_list, cb);
+}
+
static bool rssi_above_threshold(int old, int new)
{
/* only 8 dBm or more */
@@ -4313,6 +4329,14 @@ failed:
status);
}

+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);
+}
+
static void unpair_device_complete(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
@@ -4330,6 +4354,9 @@ static void unpair_device_complete(uint8_t status, uint16_t length,

update_device_state(dev, rp->addr.type, HAL_STATUS_SUCCESS, false,
false, false);
+
+ queue_foreach(unpaired_cb_list, send_unpaired_notification,
+ (void *)&rp->addr);
}

static void handle_remove_bond_cmd(const void *buf, uint16_t len)
@@ -5114,6 +5141,12 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t mode)

DBG("mode 0x%x", mode);

+ unpaired_cb_list = queue_new();
+ if (!unpaired_cb_list) {
+ error("Can not allocate queue for unpaired callbacks");
+ return false;
+ }
+
missing_settings = adapter.current_settings ^
adapter.supported_settings;

@@ -5129,7 +5162,7 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t mode)
/* Fail if controller does not support LE */
if (!(adapter.supported_settings & MGMT_SETTING_LE)) {
error("LE Mode not supported by controller");
- return false;
+ goto failed;
}

/* If LE it is not yet enabled then enable it */
@@ -5144,7 +5177,7 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t mode)
/* Fail if controller does not support BR/EDR */
if (!(adapter.supported_settings & MGMT_SETTING_BREDR)) {
error("BR/EDR Mode not supported");
- return false;
+ goto failed;
}

/* Enable BR/EDR if it is not enabled */
@@ -5162,7 +5195,7 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t mode)
break;
default:
error("Unknown mode 0x%x", mode);
- return false;
+ goto failed;
}

hal_ipc = ipc;
@@ -5171,6 +5204,10 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t mode)
G_N_ELEMENTS(cmd_handlers));

return true;
+
+failed:
+ queue_destroy(unpaired_cb_list, NULL);
+ return false;
}

void bt_bluetooth_unregister(void)
@@ -5185,4 +5222,6 @@ void bt_bluetooth_unregister(void)

ipc_unregister(hal_ipc, HAL_SERVICE_ID_CORE);
hal_ipc = NULL;
+
+ queue_destroy(unpaired_cb_list, NULL);
}
diff --git a/android/bluetooth.h b/android/bluetooth.h
index ac7f3ad..185477c 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -85,3 +85,6 @@ bool bt_kernel_conn_control(void);
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);
+bool bt_unpaired_register(bt_unpaired_device_cb cb);
--
1.8.4