2012-03-16 09:45:58

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH v3 0/6] Implement ProximityReporter profiles

This patch-set implements the Link loss and Immediate Alert GATT
server profiles.

A few API calls are added/changed in preparation, the most notable of
which is the addition of the remote-device to each GATT read/write callback.

The new profiles are separated into their own files for clarity.

A ProximityReporter D-Bus interface is registered for each remote device.
Property queries and PropertyChanged notifications are implemented, in
accordance to doc/proximity-api.txt.

v2->3: Minor function renames and commit message changes

Arik Nemtsov (6):
att: add remote btd_device to ATT read/write callbacks
proximity: reporter: save global D-Bus connection
proximity: reporter: move definitions to .h and add util function
proximity: link loss: implement link loss server
proximity: immediate alert: implement immediate alert server
proximity: reporter: implement D-Bus API

Makefile.am | 4 +-
attrib/att.h | 6 +-
plugins/gatt-example.c | 3 +-
proximity/immalert.c | 288 +++++++++++++++++++++++++++++++++++++++++
proximity/immalert.h | 26 ++++
proximity/linkloss.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++
proximity/linkloss.h | 26 ++++
proximity/reporter.c | 250 ++++++++++++++++++++++++++----------
proximity/reporter.h | 16 +++
src/attrib-server.c | 19 ++-
time/server.c | 6 +-
11 files changed, 900 insertions(+), 80 deletions(-)
create mode 100644 proximity/immalert.c
create mode 100644 proximity/immalert.h
create mode 100644 proximity/linkloss.c
create mode 100644 proximity/linkloss.h

--
1.7.5.4



2012-03-19 08:53:38

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [PATCH v3 4/6] proximity: link loss: implement link loss server

On Fri, Mar 16, 2012 at 13:49, Anderson Lizardo
<[email protected]> wrote:
> Hi Arik,
>
> On Fri, Mar 16, 2012 at 5:46 AM, Arik Nemtsov <[email protected]> wrote:
>> +static void link_Loss_local_disc(struct btd_device *device, gboolean removal,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?void *user_data)
>
> Not sure if this was already on the original series (sorry if I missed
> it), but there is a typo here:
>
> link_Loss_local_disc -> link_loss_local_disc
>

Sure i'll change it (and the other comment as well), but let's make
other wording related changes on top of upstream (it's easier).

Arik

2012-03-16 11:54:41

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [PATCH v3 5/6] proximity: immediate alert: implement immediate alert server

Hi Arik,

On Fri, Mar 16, 2012 at 5:46 AM, Arik Nemtsov <[email protected]> wrote:
> +void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn);
> +void imm_alert_unregister(struct btd_adapter *adapter);
> +const char *imm_get_alert_level(struct btd_device *device);

You may also fix this (to keep same prefix for non-local functions):

imm_get_alert_level -> imm_alert_get_level

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2012-03-16 11:49:30

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [PATCH v3 4/6] proximity: link loss: implement link loss server

Hi Arik,

On Fri, Mar 16, 2012 at 5:46 AM, Arik Nemtsov <[email protected]> wrote:
> +static void link_Loss_local_disc(struct btd_device *device, gboolean removal,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?void *user_data)

Not sure if this was already on the original series (sorry if I missed
it), but there is a typo here:

link_Loss_local_disc -> link_loss_local_disc

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2012-03-16 09:46:04

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH v3 6/6] proximity: reporter: implement D-Bus API

Use a device driver to track all GATT supporting devices and register
a D-Bus interface per remote device.

Implement the "GetProperties" method of the D-Bus interface by querying
the alert level of the remote device in the link-loss and
immediate-alert proximity profiles. The default alert level values for
non-connected devices are "none".
---
proximity/reporter.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 183 insertions(+), 8 deletions(-)

diff --git a/proximity/reporter.c b/proximity/reporter.c
index e77a6ea..2b38823 100644
--- a/proximity/reporter.c
+++ b/proximity/reporter.c
@@ -31,8 +31,14 @@
#include <adapter.h>
#include <errno.h>

+#include <dbus/dbus.h>
+#include <gdbus.h>
+
#include "log.h"

+#include "dbus-common.h"
+#include "error.h"
+#include "device.h"
#include "hcid.h"
#include "att.h"
#include "gattrib.h"
@@ -41,7 +47,39 @@
#include "linkloss.h"
#include "immalert.h"

-static DBusConnection *connection;
+#define BLUEZ_SERVICE "org.bluez"
+
+#define GATT_UUID "00001801-0000-1000-8000-00805f9b34fb"
+
+struct reporter_adapter {
+ DBusConnection *conn;
+ struct btd_adapter *adapter;
+ GSList *devices;
+};
+
+static GSList *reporter_adapters;
+
+static int radapter_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct reporter_adapter *radapter = a;
+ const struct btd_adapter *adapter = b;
+
+ if (radapter->adapter == adapter)
+ return 0;
+
+ return -1;
+}
+
+static struct reporter_adapter *
+find_reporter_adapter(struct btd_adapter *adapter)
+{
+ GSList *l = g_slist_find_custom(reporter_adapters, adapter,
+ radapter_cmp);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}

const char *get_alert_level_string(uint8_t level)
{
@@ -101,28 +139,165 @@ static void register_tx_power(struct btd_adapter *adapter)
g_assert(h - start_handle == svc_size);
}

+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ DBusMessage *reply = NULL;
+ const char *linkloss_level, *immalert_level;
+ struct btd_device *device = data;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return NULL;
+
+ linkloss_level = link_loss_get_alert_level(device);
+ immalert_level = imm_get_alert_level(device);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict))
+ goto err;
+
+ dict_append_entry(&dict, "LinkLossAlertLevel",
+ DBUS_TYPE_STRING, &linkloss_level);
+ dict_append_entry(&dict, "ImmediateAlertLevel",
+ DBUS_TYPE_STRING, &immalert_level);
+
+ if (!dbus_message_iter_close_container(&iter, &dict))
+ goto err;
+
+ return reply;
+
+err:
+ if (reply)
+ dbus_message_unref(reply);
+ return btd_error_failed(msg, "not enough memory");
+}
+
+static GDBusMethodTable reporter_methods[] = {
+ { "GetProperties", "", "a{sv}", get_properties },
+ { }
+};
+
+static GDBusSignalTable reporter_signals[] = {
+ { "PropertyChanged", "sv" },
+ { }
+};
+
+static void unregister_reporter_device(gpointer data, gpointer user_data)
+{
+ struct btd_device *device = data;
+ struct reporter_adapter *radapter = user_data;
+ const char *path = device_get_path(device);
+
+ DBG("unregister on device %s", path);
+
+ g_dbus_unregister_interface(radapter->conn, path,
+ PROXIMITY_REPORTER_INTERFACE);
+
+ radapter->devices = g_slist_remove(radapter->devices, device);
+ btd_device_unref(device);
+}
+
+static void register_reporter_device(struct btd_device *device,
+ struct reporter_adapter *radapter)
+{
+ const char *path = device_get_path(device);
+
+ DBG("register on device %s", path);
+
+ g_dbus_register_interface(radapter->conn, path,
+ PROXIMITY_REPORTER_INTERFACE,
+ reporter_methods, reporter_signals,
+ NULL, device, NULL);
+
+ btd_device_ref(device);
+ radapter->devices = g_slist_prepend(radapter->devices, device);
+}
+
+static int reporter_device_probe(struct btd_device *device, GSList *uuids)
+{
+ struct reporter_adapter *radapter;
+ struct btd_adapter *adapter = device_get_adapter(device);
+
+ radapter = find_reporter_adapter(adapter);
+ if (!radapter)
+ return -1;
+
+ register_reporter_device(device, radapter);
+ return 0;
+}
+
+static void reporter_device_remove(struct btd_device *device)
+{
+ struct reporter_adapter *radapter;
+ struct btd_adapter *adapter = device_get_adapter(device);
+
+ radapter = find_reporter_adapter(adapter);
+ if (!radapter)
+ return;
+
+ unregister_reporter_device(device, radapter);
+}
+
+/* device driver for tracking remote GATT client devices */
+static struct btd_device_driver reporter_device_driver = {
+ .name = "Proximity GATT Reporter Device Tracker Driver",
+ .uuids = BTD_UUIDS(GATT_UUID),
+ .probe = reporter_device_probe,
+ .remove = reporter_device_remove,
+};
+
int reporter_init(struct btd_adapter *adapter)
{
+ struct reporter_adapter *radapter;
+ DBusConnection *conn;
+
if (!main_opts.attrib_server) {
DBG("Attribute server is disabled");
return -1;
}

- connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
- if (connection == NULL)
- return -EIO;
- DBG("Proximity Reporter for adapter %p", adapter);
+ conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (!conn)
+ return -1;
+
+ radapter = g_new0(struct reporter_adapter, 1);
+ radapter->adapter = adapter;
+ radapter->conn = conn;

- link_loss_register(adapter, connection);
+ link_loss_register(adapter, radapter->conn);
register_tx_power(adapter);
- imm_alert_register(adapter, connection);
+ imm_alert_register(adapter, radapter->conn);
+
+ btd_register_device_driver(&reporter_device_driver);
+
+ reporter_adapters = g_slist_prepend(reporter_adapters, radapter);
+ DBG("Proximity Reporter for adapter %p", adapter);

return 0;
}

void reporter_exit(struct btd_adapter *adapter)
{
+ struct reporter_adapter *radapter = find_reporter_adapter(adapter);
+ if (!radapter)
+ return;
+
+ btd_unregister_device_driver(&reporter_device_driver);
+
+ g_slist_foreach(radapter->devices, unregister_reporter_device,
+ radapter);
+
link_loss_unregister(adapter);
imm_alert_unregister(adapter);
- dbus_connection_unref(connection);
+ dbus_connection_unref(radapter->conn);
+
+ reporter_adapters = g_slist_remove(reporter_adapters, radapter);
+ g_free(radapter);
}
--
1.7.5.4


2012-03-16 09:46:03

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH v3 5/6] proximity: immediate alert: implement immediate alert server

The profile is implemented in immalert.[ch]. A GATT service is
registered with a write callback on the immediate alert level attribute.
This attribute is write-only and is maintained per remote device.

When a remote device write a raises or lowers the alert level,
an appropriate PropertyChanged signal is emitted. When the alert level
of a device is non-zero, a callback is registered on its disconnection.
When the callback is called, the alert level of the device is reset to
zero and an appropriate signal is emitted.
---
Makefile.am | 3 +-
proximity/immalert.c | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++
proximity/immalert.h | 26 +++++
proximity/reporter.c | 42 +-------
4 files changed, 319 insertions(+), 40 deletions(-)
create mode 100644 proximity/immalert.c
create mode 100644 proximity/immalert.h

diff --git a/Makefile.am b/Makefile.am
index 0a253af..0295ce2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -205,7 +205,8 @@ builtin_sources += proximity/main.c \
proximity/manager.h proximity/manager.c \
proximity/monitor.h proximity/monitor.c \
proximity/reporter.h proximity/reporter.c \
- proximity/linkloss.h proximity/linkloss.c
+ proximity/linkloss.h proximity/linkloss.c \
+ proximity/immalert.h proximity/immalert.c
endif

if SERVICEPLUGIN
diff --git a/proximity/immalert.c b/proximity/immalert.c
new file mode 100644
index 0000000..6fd4b8e
--- /dev/null
+++ b/proximity/immalert.c
@@ -0,0 +1,288 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <bluetooth/uuid.h>
+#include <adapter.h>
+
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "log.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt-service.h"
+#include "attrib-server.h"
+#include "device.h"
+#include "attio.h"
+#include "dbus-common.h"
+#include "reporter.h"
+#include "immalert.h"
+
+struct imm_alert_adapter {
+ struct btd_adapter *adapter;
+ DBusConnection *conn;
+ GSList *connected_devices;
+};
+
+struct connected_device {
+ struct btd_device *device;
+ struct imm_alert_adapter *adapter;
+ uint8_t alert_level;
+ guint callback_id;
+};
+
+static GSList *imm_alert_adapters;
+
+static int imdevice_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct connected_device *condev = a;
+ const struct btd_device *device = b;
+
+ if (condev->device == device)
+ return 0;
+
+ return -1;
+}
+
+static struct connected_device *
+find_connected_device(struct imm_alert_adapter *ia, struct btd_device *device)
+{
+ GSList *l = g_slist_find_custom(ia->connected_devices, device,
+ imdevice_cmp);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
+static int imadapter_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct imm_alert_adapter *imadapter = a;
+ const struct btd_adapter *adapter = b;
+
+ if (imadapter->adapter == adapter)
+ return 0;
+
+ return -1;
+}
+
+static struct imm_alert_adapter *
+find_imm_alert_adapter(struct btd_adapter *adapter)
+{
+ GSList *l = g_slist_find_custom(imm_alert_adapters, adapter,
+ imadapter_cmp);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
+const char *imm_get_alert_level(struct btd_device *device)
+{
+ struct imm_alert_adapter *imadapter;
+ struct connected_device *condev;
+
+ if (!device)
+ return get_alert_level_string(NO_ALERT);
+
+ imadapter = find_imm_alert_adapter(device_get_adapter(device));
+ if (!imadapter)
+ return get_alert_level_string(NO_ALERT);
+
+ condev = find_connected_device(imadapter, device);
+ if (!condev)
+ return get_alert_level_string(NO_ALERT);
+
+ return get_alert_level_string(condev->alert_level);
+}
+
+static void imm_alert_emit_alert_signal(struct connected_device *condev,
+ uint8_t alert_level)
+{
+ struct imm_alert_adapter *adapter;
+ const char *path, *alert_level_str;
+
+ if (!condev)
+ return;
+
+ adapter = condev->adapter;
+ path = device_get_path(condev->device);
+ alert_level_str = get_alert_level_string(alert_level);
+
+ DBG("alert %s remote %s", alert_level_str, path);
+
+ emit_property_changed(adapter->conn, path,
+ PROXIMITY_REPORTER_INTERFACE, "ImmediateAlertLevel",
+ DBUS_TYPE_STRING, &alert_level_str);
+}
+
+static void imm_alert_remove_condev(struct connected_device *condev)
+{
+ struct imm_alert_adapter *ia;
+
+ if (!condev)
+ return;
+
+ ia = condev->adapter;
+
+ if (condev->callback_id && condev->device)
+ btd_device_remove_attio_callback(condev->device,
+ condev->callback_id);
+
+ if (condev->device)
+ btd_device_unref(condev->device);
+
+ ia->connected_devices = g_slist_remove(ia->connected_devices, condev);
+ g_free(condev);
+}
+
+/* condev can be NULL */
+static void imm_alert_disc_cb(gpointer user_data)
+{
+ struct connected_device *condev = user_data;
+
+ if (!condev)
+ return;
+
+ DBG("immediate alert remove device %p", condev->device);
+
+ imm_alert_emit_alert_signal(condev, NO_ALERT);
+ imm_alert_remove_condev(condev);
+}
+
+static uint8_t imm_alert_alert_lvl_write(struct attribute *a,
+ gpointer user_data, struct btd_device *device)
+{
+ uint8_t value;
+ struct imm_alert_adapter *ia = user_data;
+ struct connected_device *condev = NULL;
+
+ if (!device)
+ goto set_error;
+
+ condev = find_connected_device(ia, device);
+
+ if (a->len == 0) {
+ DBG("Illegal alert level length");
+ goto set_error;
+ }
+
+ value = a->data[0];
+ if (value != NO_ALERT && value != MILD_ALERT && value != HIGH_ALERT) {
+ DBG("Illegal alert value");
+ goto set_error;
+ }
+
+ /* Register a disconnect cb if the alert level is non-zero */
+ if (value != NO_ALERT && !condev) {
+ condev = g_new0(struct connected_device, 1);
+ condev->device = btd_device_ref(device);
+ condev->adapter = ia;
+ condev->callback_id = btd_device_add_attio_callback(device,
+ NULL, imm_alert_disc_cb, condev);
+ ia->connected_devices = g_slist_append(ia->connected_devices,
+ condev);
+ DBG("added connected dev %p", device);
+ }
+
+ if (value != NO_ALERT) {
+ condev->alert_level = value;
+ imm_alert_emit_alert_signal(condev, value);
+ }
+
+ /*
+ * Emit NO_ALERT if the alert level was non-zero before. This is
+ * guaranteed when there's a condev.
+ */
+ if (value == NO_ALERT && condev)
+ imm_alert_disc_cb(condev);
+
+ DBG("alert level set to %d by device %p", value, device);
+ return 0;
+
+set_error:
+ error("Set immediate alert level for dev %p", device);
+ /* remove alerts by erroneous devices */
+ imm_alert_disc_cb(condev);
+ return ATT_ECODE_IO;
+}
+
+void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn)
+{
+ gboolean svc_added;
+ bt_uuid_t uuid;
+ struct imm_alert_adapter *imadapter;
+
+ bt_uuid16_create(&uuid, IMMEDIATE_ALERT_SVC_UUID);
+
+ imadapter = g_new0(struct imm_alert_adapter, 1);
+ imadapter->adapter = adapter;
+ imadapter->conn = dbus_connection_ref(conn);
+
+ imm_alert_adapters = g_slist_append(imm_alert_adapters, imadapter);
+
+ /* Immediate Alert Service */
+ svc_added = gatt_service_add(adapter,
+ GATT_PRIM_SVC_UUID, &uuid,
+ /* Alert level characteristic */
+ GATT_OPT_CHR_UUID, ALERT_LEVEL_CHR_UUID,
+ GATT_OPT_CHR_PROPS,
+ ATT_CHAR_PROPER_WRITE_WITHOUT_RESP,
+ GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
+ imm_alert_alert_lvl_write, imadapter,
+ GATT_OPT_INVALID);
+
+ if (!svc_added) {
+ imm_alert_unregister(adapter);
+ return;
+ }
+
+ DBG("Immediate Alert service added");
+}
+
+static void remove_condev_list_item(gpointer data, gpointer user_data)
+{
+ struct connected_device *condev = data;
+
+ imm_alert_remove_condev(condev);
+}
+
+void imm_alert_unregister(struct btd_adapter *adapter)
+{
+ struct imm_alert_adapter *imadapter;
+
+ imadapter = find_imm_alert_adapter(adapter);
+ if (!adapter)
+ return;
+
+ g_slist_foreach(imadapter->connected_devices, remove_condev_list_item,
+ NULL);
+ dbus_connection_unref(imadapter->conn);
+
+ imm_alert_adapters = g_slist_remove(imm_alert_adapters, imadapter);
+ g_free(imadapter);
+}
diff --git a/proximity/immalert.h b/proximity/immalert.h
new file mode 100644
index 0000000..6b43911
--- /dev/null
+++ b/proximity/immalert.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn);
+void imm_alert_unregister(struct btd_adapter *adapter);
+const char *imm_get_alert_level(struct btd_device *device);
diff --git a/proximity/reporter.c b/proximity/reporter.c
index d362849..e77a6ea 100644
--- a/proximity/reporter.c
+++ b/proximity/reporter.c
@@ -39,6 +39,7 @@
#include "attrib-server.h"
#include "reporter.h"
#include "linkloss.h"
+#include "immalert.h"

static DBusConnection *connection;

@@ -100,44 +101,6 @@ static void register_tx_power(struct btd_adapter *adapter)
g_assert(h - start_handle == svc_size);
}

-static void register_immediate_alert(struct btd_adapter *adapter)
-{
- uint16_t start_handle, h;
- const int svc_size = 3;
- uint8_t atval[256];
- bt_uuid_t uuid;
-
- bt_uuid16_create(&uuid, IMMEDIATE_ALERT_SVC_UUID);
- start_handle = attrib_db_find_avail(adapter, &uuid, svc_size);
- if (start_handle == 0) {
- error("Not enough free handles to register service");
- return;
- }
-
- DBG("start_handle=0x%04x", start_handle);
-
- h = start_handle;
-
- /* Primary service definition */
- bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
- att_put_u16(IMMEDIATE_ALERT_SVC_UUID, &atval[0]);
- attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
-
- /* Alert level characteristic */
- bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
- atval[0] = ATT_CHAR_PROPER_WRITE_WITHOUT_RESP;
- att_put_u16(h + 1, &atval[1]);
- att_put_u16(ALERT_LEVEL_CHR_UUID, &atval[3]);
- attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
-
- /* Alert level value */
- bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID);
- att_put_u8(NO_ALERT, &atval[0]);
- attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NONE, atval, 1);
-
- g_assert(h - start_handle == svc_size);
-}
-
int reporter_init(struct btd_adapter *adapter)
{
if (!main_opts.attrib_server) {
@@ -152,7 +115,7 @@ int reporter_init(struct btd_adapter *adapter)

link_loss_register(adapter, connection);
register_tx_power(adapter);
- register_immediate_alert(adapter);
+ imm_alert_register(adapter, connection);

return 0;
}
@@ -160,5 +123,6 @@ int reporter_init(struct btd_adapter *adapter)
void reporter_exit(struct btd_adapter *adapter)
{
link_loss_unregister(adapter);
+ imm_alert_unregister(adapter);
dbus_connection_unref(connection);
}
--
1.7.5.4


2012-03-16 09:46:02

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH v3 4/6] proximity: link loss: implement link loss server

The profile is implemented in linkloss.[ch]. A GATT service is
registered with read/write callbacks on the link-loss alert level
attribute. The alert level is maintained per device. It is returned
on read and updated on write.

When the alert level is non-zero, a callback is registered on the
disconnection of the remote device. If a device with non-zero alert
state is disconnected, an appropriate PropertyChanged signal is emitted
with the alert level previously set by the device. We avoid emitting
a signal when the disconnection was requested by us.
---
Makefile.am | 3 +-
proximity/linkloss.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++
proximity/linkloss.h | 26 ++++
proximity/reporter.c | 42 +------
4 files changed, 367 insertions(+), 40 deletions(-)
create mode 100644 proximity/linkloss.c
create mode 100644 proximity/linkloss.h

diff --git a/Makefile.am b/Makefile.am
index bd587eb..0a253af 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -204,7 +204,8 @@ builtin_modules += proximity
builtin_sources += proximity/main.c \
proximity/manager.h proximity/manager.c \
proximity/monitor.h proximity/monitor.c \
- proximity/reporter.h proximity/reporter.c
+ proximity/reporter.h proximity/reporter.c \
+ proximity/linkloss.h proximity/linkloss.c
endif

if SERVICEPLUGIN
diff --git a/proximity/linkloss.c b/proximity/linkloss.c
new file mode 100644
index 0000000..7f63cb7
--- /dev/null
+++ b/proximity/linkloss.c
@@ -0,0 +1,336 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <bluetooth/uuid.h>
+#include <adapter.h>
+
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "log.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt-service.h"
+#include "attrib-server.h"
+#include "device.h"
+#include "attio.h"
+#include "dbus-common.h"
+#include "reporter.h"
+#include "linkloss.h"
+
+#define BLUEZ_SERVICE "org.bluez"
+
+struct link_loss_adapter {
+ struct btd_adapter *adapter;
+ uint16_t alert_lvl_value_handle;
+ DBusConnection *conn;
+ GSList *connected_devices;
+};
+
+struct connected_device {
+ struct btd_device *device;
+ struct link_loss_adapter *adapter;
+ uint8_t alert_level;
+ guint callback_id;
+ guint local_disc_id;
+};
+
+static GSList *link_loss_adapters;
+
+static int lldevice_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct connected_device *llcondev = a;
+ const struct btd_device *device = b;
+
+ if (llcondev->device == device)
+ return 0;
+
+ return -1;
+}
+
+static struct connected_device *
+find_connected_device(struct link_loss_adapter *la, struct btd_device *device)
+{
+ GSList *l = g_slist_find_custom(la->connected_devices, device,
+ lldevice_cmp);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
+static int lladapter_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct link_loss_adapter *lladapter = a;
+ const struct btd_adapter *adapter = b;
+
+ if (lladapter->adapter == adapter)
+ return 0;
+
+ return -1;
+}
+
+static struct link_loss_adapter *
+find_link_loss_adapter(struct btd_adapter *adapter)
+{
+ GSList *l = g_slist_find_custom(link_loss_adapters, adapter,
+ lladapter_cmp);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
+const char *link_loss_get_alert_level(struct btd_device *device)
+{
+ struct link_loss_adapter *lladapter;
+ struct connected_device *condev;
+
+ if (!device)
+ return get_alert_level_string(NO_ALERT);
+
+ lladapter = find_link_loss_adapter(device_get_adapter(device));
+ if (!lladapter)
+ return get_alert_level_string(NO_ALERT);
+
+ condev = find_connected_device(lladapter, device);
+ if (!condev)
+ return get_alert_level_string(NO_ALERT);
+
+ return get_alert_level_string(condev->alert_level);
+}
+
+static void link_loss_emit_alert_signal(struct connected_device *condev)
+{
+ struct link_loss_adapter *adapter = condev->adapter;
+ const char *alert_level_str, *path;
+
+ if (!condev->device)
+ return;
+
+ path = device_get_path(condev->device);
+ alert_level_str = get_alert_level_string(condev->alert_level);
+
+ DBG("alert %s remote %s", alert_level_str, path);
+
+ emit_property_changed(adapter->conn, path,
+ PROXIMITY_REPORTER_INTERFACE, "LinkLossAlertLevel",
+ DBUS_TYPE_STRING, &alert_level_str);
+}
+
+static uint8_t link_loss_alert_lvl_read(struct attribute *a, gpointer user_data,
+ struct btd_device *device)
+{
+ struct link_loss_adapter *la = user_data;
+ struct connected_device *condev;
+ uint8_t alert_level = NO_ALERT;
+
+ if (!device)
+ goto out;
+
+ condev = find_connected_device(la, device);
+ if (!condev)
+ goto out;
+
+ alert_level = condev->alert_level;
+
+out:
+ DBG("return alert level %d for dev %p", alert_level, device);
+
+ /* update the alert level according to the requesting device */
+ attrib_db_update(la->adapter, a->handle, NULL, &alert_level,
+ sizeof(alert_level), NULL);
+
+ return 0;
+}
+
+/* condev can be NULL */
+static void link_loss_remove_condev(struct connected_device *condev)
+{
+ struct link_loss_adapter *la;
+
+ if (!condev)
+ return;
+
+ la = condev->adapter;
+
+ if (condev->callback_id && condev->device)
+ btd_device_remove_attio_callback(condev->device,
+ condev->callback_id);
+
+ if (condev->local_disc_id && condev->device)
+ device_remove_disconnect_watch(condev->device,
+ condev->local_disc_id);
+
+ if (condev->device)
+ btd_device_unref(condev->device);
+
+ la->connected_devices = g_slist_remove(la->connected_devices, condev);
+ g_free(condev);
+}
+
+static void link_loss_disc_cb(gpointer user_data)
+{
+ struct connected_device *condev = user_data;
+
+ DBG("alert loss disconnect device %p", condev->device);
+
+ /* if an alert-level is set, emit a signal */
+ if (condev->alert_level != NO_ALERT)
+ link_loss_emit_alert_signal(condev);
+
+ /* we are open for more changes now */
+ link_loss_remove_condev(condev);
+}
+
+static void link_Loss_local_disc(struct btd_device *device, gboolean removal,
+ void *user_data)
+{
+ struct connected_device *condev = user_data;
+
+ /* no need to alert on this device - we requested disconnection */
+ link_loss_remove_condev(condev);
+
+ DBG("alert level zeroed for locally disconnecting dev %p", device);
+}
+
+static uint8_t link_loss_alert_lvl_write(struct attribute *a,
+ gpointer user_data, struct btd_device *device)
+{
+ uint8_t value;
+ struct link_loss_adapter *la = user_data;
+ struct connected_device *condev = NULL;
+
+ if (!device)
+ goto set_error;
+
+ /* condev might remain NULL here if nothing is found */
+ condev = find_connected_device(la, device);
+
+ if (a->len == 0) {
+ DBG("Illegal alert level length");
+ goto set_error;
+ }
+
+ value = a->data[0];
+ if (value != NO_ALERT && value != MILD_ALERT && value != HIGH_ALERT) {
+ DBG("Illegal alert value");
+ goto set_error;
+ }
+
+ /* Register a disconnect cb if the alert level is non-zero */
+ if (value != NO_ALERT && !condev) {
+ condev = g_new0(struct connected_device, 1);
+ condev->device = btd_device_ref(device);
+ condev->adapter = la;
+ condev->callback_id = btd_device_add_attio_callback(device,
+ NULL, link_loss_disc_cb, condev);
+ condev->local_disc_id = device_add_disconnect_watch(device,
+ link_Loss_local_disc, condev, NULL);
+
+ la->connected_devices = g_slist_append(la->connected_devices,
+ condev);
+ } else if (value == NO_ALERT && condev) {
+ link_loss_remove_condev(condev);
+ condev = NULL;
+ }
+
+ DBG("alert level set to %d by device %p", value, device);
+
+ if (condev)
+ condev->alert_level = value;
+
+ return 0;
+
+set_error:
+ error("Set link loss alert level for dev %p", device);
+ /* reset alert level on erroneous devices */
+ link_loss_remove_condev(condev);
+ return ATT_ECODE_IO;
+}
+
+void link_loss_register(struct btd_adapter *adapter, DBusConnection *conn)
+{
+ gboolean svc_added;
+ bt_uuid_t uuid;
+ struct link_loss_adapter *lladapter;
+
+ bt_uuid16_create(&uuid, LINK_LOSS_SVC_UUID);
+
+ lladapter = g_new0(struct link_loss_adapter, 1);
+ lladapter->adapter = adapter;
+ lladapter->conn = dbus_connection_ref(conn);
+
+ link_loss_adapters = g_slist_append(link_loss_adapters, lladapter);
+
+ /* Link Loss Service */
+ svc_added = gatt_service_add(adapter,
+ GATT_PRIM_SVC_UUID, &uuid,
+ /* Alert level characteristic */
+ GATT_OPT_CHR_UUID, ALERT_LEVEL_CHR_UUID,
+ GATT_OPT_CHR_PROPS,
+ ATT_CHAR_PROPER_READ | ATT_CHAR_PROPER_WRITE,
+ GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+ link_loss_alert_lvl_read, lladapter,
+ GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
+ link_loss_alert_lvl_write, lladapter,
+ GATT_OPT_CHR_VALUE_GET_HANDLE,
+ &lladapter->alert_lvl_value_handle,
+ GATT_OPT_INVALID);
+
+ if (!svc_added)
+ goto err;
+
+ DBG("Link Loss service added");
+ return;
+
+err:
+ error("Error adding Link Loss service");
+ link_loss_unregister(adapter);
+}
+
+static void remove_condev_list_item(gpointer data, gpointer user_data)
+{
+ struct connected_device *condev = data;
+
+ link_loss_remove_condev(condev);
+}
+
+void link_loss_unregister(struct btd_adapter *adapter)
+{
+ struct link_loss_adapter *lladapter;
+ lladapter = find_link_loss_adapter(adapter);
+ if (!lladapter)
+ return;
+
+ g_slist_foreach(lladapter->connected_devices, remove_condev_list_item,
+ NULL);
+ dbus_connection_unref(lladapter->conn);
+
+ link_loss_adapters = g_slist_remove(link_loss_adapters, lladapter);
+ g_free(lladapter);
+}
diff --git a/proximity/linkloss.h b/proximity/linkloss.h
new file mode 100644
index 0000000..a7d83d0
--- /dev/null
+++ b/proximity/linkloss.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void link_loss_register(struct btd_adapter *adapter, DBusConnection *conn);
+void link_loss_unregister(struct btd_adapter *adapter);
+const char *link_loss_get_alert_level(struct btd_device *device);
diff --git a/proximity/reporter.c b/proximity/reporter.c
index e9dbc9f..d362849 100644
--- a/proximity/reporter.c
+++ b/proximity/reporter.c
@@ -38,6 +38,7 @@
#include "gattrib.h"
#include "attrib-server.h"
#include "reporter.h"
+#include "linkloss.h"

static DBusConnection *connection;

@@ -55,44 +56,6 @@ const char *get_alert_level_string(uint8_t level)
return "unknown";
}

-static void register_link_loss(struct btd_adapter *adapter)
-{
- uint16_t start_handle, h;
- const int svc_size = 3;
- uint8_t atval[256];
- bt_uuid_t uuid;
-
- bt_uuid16_create(&uuid, LINK_LOSS_SVC_UUID);
- start_handle = attrib_db_find_avail(adapter, &uuid, svc_size);
- if (start_handle == 0) {
- error("Not enough free handles to register service");
- return;
- }
-
- DBG("start_handle=0x%04x", start_handle);
-
- h = start_handle;
-
- /* Primary service definition */
- bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
- att_put_u16(LINK_LOSS_SVC_UUID, &atval[0]);
- attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
-
- /* Alert level characteristic */
- bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
- atval[0] = ATT_CHAR_PROPER_READ | ATT_CHAR_PROPER_WRITE;
- att_put_u16(h + 1, &atval[1]);
- att_put_u16(ALERT_LEVEL_CHR_UUID, &atval[3]);
- attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
-
- /* Alert level value */
- bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID);
- att_put_u8(NO_ALERT, &atval[0]);
- attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NONE, atval, 1);
-
- g_assert(h - start_handle == svc_size);
-}
-
static void register_tx_power(struct btd_adapter *adapter)
{
uint16_t start_handle, h;
@@ -187,7 +150,7 @@ int reporter_init(struct btd_adapter *adapter)
return -EIO;
DBG("Proximity Reporter for adapter %p", adapter);

- register_link_loss(adapter);
+ link_loss_register(adapter, connection);
register_tx_power(adapter);
register_immediate_alert(adapter);

@@ -196,5 +159,6 @@ int reporter_init(struct btd_adapter *adapter)

void reporter_exit(struct btd_adapter *adapter)
{
+ link_loss_unregister(adapter);
dbus_connection_unref(connection);
}
--
1.7.5.4


2012-03-16 09:46:01

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH v3 3/6] proximity: reporter: move definitions to .h and add util function

This allows us to re-use these definitions in GATT sub-profiles.
---
proximity/reporter.c | 25 ++++++++++++++-----------
proximity/reporter.h | 16 ++++++++++++++++
2 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/proximity/reporter.c b/proximity/reporter.c
index f7744f5..e9dbc9f 100644
--- a/proximity/reporter.c
+++ b/proximity/reporter.c
@@ -40,17 +40,20 @@
#include "reporter.h"

static DBusConnection *connection;
-#define IMMEDIATE_ALERT_SVC_UUID 0x1802
-#define LINK_LOSS_SVC_UUID 0x1803
-#define TX_POWER_SVC_UUID 0x1804
-#define ALERT_LEVEL_CHR_UUID 0x2A06
-#define POWER_LEVEL_CHR_UUID 0x2A07
-
-enum {
- NO_ALERT = 0x00,
- MILD_ALERT = 0x01,
- HIGH_ALERT = 0x02,
-};
+
+const char *get_alert_level_string(uint8_t level)
+{
+ switch (level) {
+ case NO_ALERT:
+ return "none";
+ case MILD_ALERT:
+ return "mild";
+ case HIGH_ALERT:
+ return "high";
+ }
+
+ return "unknown";
+}

static void register_link_loss(struct btd_adapter *adapter)
{
diff --git a/proximity/reporter.h b/proximity/reporter.h
index 2b18446..5ae0eb2 100644
--- a/proximity/reporter.h
+++ b/proximity/reporter.h
@@ -22,5 +22,21 @@
*
*/

+#define PROXIMITY_REPORTER_INTERFACE "org.bluez.ProximityReporter"
+
+#define IMMEDIATE_ALERT_SVC_UUID 0x1802
+#define LINK_LOSS_SVC_UUID 0x1803
+#define TX_POWER_SVC_UUID 0x1804
+#define ALERT_LEVEL_CHR_UUID 0x2A06
+#define POWER_LEVEL_CHR_UUID 0x2A07
+
+enum {
+ NO_ALERT = 0x00,
+ MILD_ALERT = 0x01,
+ HIGH_ALERT = 0x02,
+};
+
int reporter_init(struct btd_adapter *adapter);
void reporter_exit(struct btd_adapter *adapter);
+
+const char *get_alert_level_string(uint8_t level);
--
1.7.5.4


2012-03-16 09:46:00

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH v3 2/6] proximity: reporter: save global D-Bus connection

This connection will be used by reporter GATT sub-profiles.
---
proximity/reporter.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/proximity/reporter.c b/proximity/reporter.c
index 9777574..f7744f5 100644
--- a/proximity/reporter.c
+++ b/proximity/reporter.c
@@ -29,6 +29,7 @@
#include <glib.h>
#include <bluetooth/uuid.h>
#include <adapter.h>
+#include <errno.h>

#include "log.h"

@@ -38,6 +39,7 @@
#include "attrib-server.h"
#include "reporter.h"

+static DBusConnection *connection;
#define IMMEDIATE_ALERT_SVC_UUID 0x1802
#define LINK_LOSS_SVC_UUID 0x1803
#define TX_POWER_SVC_UUID 0x1804
@@ -177,6 +179,9 @@ int reporter_init(struct btd_adapter *adapter)
return -1;
}

+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (connection == NULL)
+ return -EIO;
DBG("Proximity Reporter for adapter %p", adapter);

register_link_loss(adapter);
@@ -188,4 +193,5 @@ int reporter_init(struct btd_adapter *adapter)

void reporter_exit(struct btd_adapter *adapter)
{
+ dbus_connection_unref(connection);
}
--
1.7.5.4


2012-03-16 09:45:59

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH v3 1/6] att: add remote btd_device to ATT read/write callbacks

This allows us to identify the remote device that made the ATT
read/write.
---
attrib/att.h | 6 ++++--
plugins/gatt-example.c | 3 ++-
src/attrib-server.c | 19 ++++++++++++++-----
time/server.c | 6 ++++--
4 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/attrib/att.h b/attrib/att.h
index dc266f1..70f3d91 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -130,8 +130,10 @@ struct attribute {
bt_uuid_t uuid;
int read_reqs;
int write_reqs;
- uint8_t (*read_cb)(struct attribute *a, gpointer user_data);
- uint8_t (*write_cb)(struct attribute *a, gpointer user_data);
+ uint8_t (*read_cb)(struct attribute *a, gpointer user_data,
+ gpointer device);
+ uint8_t (*write_cb)(struct attribute *a, gpointer user_data,
+ gpointer device);
gpointer cb_user_data;
int len;
uint8_t *data;
diff --git a/plugins/gatt-example.c b/plugins/gatt-example.c
index f026761..ad5b844 100644
--- a/plugins/gatt-example.c
+++ b/plugins/gatt-example.c
@@ -92,7 +92,8 @@ static gint adapter_cmp(gconstpointer a, gconstpointer b)
return -1;
}

-static uint8_t battery_state_read(struct attribute *a, gpointer user_data)
+static uint8_t battery_state_read(struct attribute *a, gpointer user_data,
+ struct btd_device *device)
{
struct btd_adapter *adapter = user_data;
uint8_t value;
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 5775861..e88eb1c 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -76,6 +76,7 @@ struct gatt_channel {
gboolean encrypted;
struct gatt_server *server;
guint cleanup_id;
+ struct btd_device *device;
};

struct group_elem {
@@ -112,6 +113,9 @@ static void channel_free(struct gatt_channel *channel)
if (channel->cleanup_id)
g_source_remove(channel->cleanup_id);

+ if (channel->device)
+ btd_device_unref(channel->device);
+
g_attrib_unref(channel->attrib);
g_free(channel);
}
@@ -452,7 +456,8 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
a->read_reqs);

if (status == 0x00 && a->read_cb)
- status = a->read_cb(a, a->cb_user_data);
+ status = a->read_cb(a, a->cb_user_data,
+ channel->device);

if (status) {
g_slist_free_full(groups, g_free);
@@ -541,7 +546,8 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
a->read_reqs);

if (status == 0x00 && a->read_cb)
- status = a->read_cb(a, a->cb_user_data);
+ status = a->read_cb(a, a->cb_user_data,
+ channel->device);

if (status) {
g_slist_free(types);
@@ -753,7 +759,7 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
status = att_check_reqs(channel, ATT_OP_READ_REQ, a->read_reqs);

if (status == 0x00 && a->read_cb)
- status = a->read_cb(a, a->cb_user_data);
+ status = a->read_cb(a, a->cb_user_data, channel->device);

if (status)
return enc_error_resp(ATT_OP_READ_REQ, handle, status, pdu,
@@ -796,7 +802,7 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
status = att_check_reqs(channel, ATT_OP_READ_BLOB_REQ, a->read_reqs);

if (status == 0x00 && a->read_cb)
- status = a->read_cb(a, a->cb_user_data);
+ status = a->read_cb(a, a->cb_user_data, channel->device);

if (status)
return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, status,
@@ -833,7 +839,8 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
value, vlen, NULL);

if (a->write_cb) {
- status = a->write_cb(a, a->cb_user_data);
+ status = a->write_cb(a, a->cb_user_data,
+ channel->device);
if (status)
return enc_error_resp(ATT_OP_WRITE_REQ, handle,
status, pdu, len);
@@ -1067,6 +1074,8 @@ guint attrib_channel_attach(GAttrib *attrib)
channel->cleanup_id = g_io_add_watch(io, G_IO_HUP, channel_watch_cb,
channel);

+ channel->device = btd_device_ref(device);
+
server->clients = g_slist_append(server->clients, channel);

return channel->id;
diff --git a/time/server.c b/time/server.c
index 42b12e2..4a2e168 100644
--- a/time/server.c
+++ b/time/server.c
@@ -78,7 +78,8 @@ static int encode_current_time(uint8_t value[10])
return 0;
}

-static uint8_t current_time_read(struct attribute *a, gpointer user_data)
+static uint8_t current_time_read(struct attribute *a, gpointer user_data,
+ struct btd_device *device)
{
uint8_t value[10];

@@ -91,7 +92,8 @@ static uint8_t current_time_read(struct attribute *a, gpointer user_data)
return 0;
}

-static uint8_t local_time_info_read(struct attribute *a, gpointer user_data)
+static uint8_t local_time_info_read(struct attribute *a, gpointer user_data,
+ struct btd_device *device)
{
uint8_t value[2];

--
1.7.5.4