* [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue
@ 2016-05-09 13:51 Luiz Augusto von Dentz
2016-05-09 13:51 ` [PATCHv2 BlueZ 2/6] doc/gatt-api: Merge RegisterProfile with RegisterApplication Luiz Augusto von Dentz
` (6 more replies)
0 siblings, 7 replies; 13+ messages in thread
From: Luiz Augusto von Dentz @ 2016-05-09 13:51 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds the possibility to pass an offset to these operations, and
also in the server case to give the device object.
---
v2: Fix Vinicius comments, add necessary changes to other tools affected.
doc/gatt-api.txt | 20 ++++-
src/gatt-client.c | 180 ++++++++++++++++++++++++++++--------------
src/gatt-database.c | 219 ++++++++++++++++++++++++++++++++++++++--------------
3 files changed, 296 insertions(+), 123 deletions(-)
diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
index ad2ab16..683b1b7 100644
--- a/doc/gatt-api.txt
+++ b/doc/gatt-api.txt
@@ -61,23 +61,29 @@ Service org.bluez
Interface org.bluez.GattCharacteristic1 [Experimental]
Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY
-Methods array{byte} ReadValue()
+Methods array{byte} ReadValue(dict options)
Issues a request to read the value of the
characteristic and returns the value if the
operation was successful.
+ Possible options: "offset": uint16 offset
+ "device": Object Device (Server only)
+
Possible Errors: org.bluez.Error.Failed
org.bluez.Error.InProgress
org.bluez.Error.NotPermitted
org.bluez.Error.NotAuthorized
org.bluez.Error.NotSupported
- void WriteValue(array{byte} value)
+ void WriteValue(array{byte} value, dict options)
Issues a request to write the value of the
characteristic.
+ Possible options: "offset": Start offset
+ "device": Device path (Server only)
+
Possible Errors: org.bluez.Error.Failed
org.bluez.Error.InProgress
org.bluez.Error.NotPermitted
@@ -154,23 +160,29 @@ Service org.bluez
Interface org.bluez.GattDescriptor1 [Experimental]
Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY/descriptorZZZ
-Methods array{byte} ReadValue()
+Methods array{byte} ReadValue(dict flags)
Issues a request to read the value of the
characteristic and returns the value if the
operation was successful.
+ Possible options: "offset": Start offset
+ "device": Device path (Server only)
+
Possible Errors: org.bluez.Error.Failed
org.bluez.Error.InProgress
org.bluez.Error.NotPermitted
org.bluez.Error.NotAuthorized
org.bluez.Error.NotSupported
- void WriteValue(array{byte} value)
+ void WriteValue(array{byte} value, dict flags)
Issues a request to write the value of the
characteristic.
+ Possible options: "offset": Start offset
+ "device": Device path (Server only)
+
Possible Errors: org.bluez.Error.Failed
org.bluez.Error.InProgress
org.bluez.Error.NotPermitted
diff --git a/src/gatt-client.c b/src/gatt-client.c
index 16a1f6c..0cbacca 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -23,6 +23,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include <errno.h>
#include <dbus/dbus.h>
@@ -191,33 +192,17 @@ static gboolean descriptor_value_exists(const GDBusPropertyTable *property,
return ret;
}
-static bool parse_value_arg(DBusMessage *msg, uint8_t **value,
- size_t *value_len)
+static int parse_value_arg(DBusMessageIter *iter, uint8_t **value, int *len)
{
- DBusMessageIter iter, array;
- uint8_t *val;
- int len;
-
- if (!dbus_message_iter_init(msg, &iter))
- return false;
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
- return false;
-
- dbus_message_iter_recurse(&iter, &array);
- dbus_message_iter_get_fixed_array(&array, &val, &len);
- dbus_message_iter_next(&iter);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID)
- return false;
+ DBusMessageIter array;
- if (len < 0)
- return false;
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return -EINVAL;
- *value = val;
- *value_len = len;
+ dbus_message_iter_recurse(iter, &array);
+ dbus_message_iter_get_fixed_array(&array, value, len);
- return true;
+ return 0;
}
typedef bool (*async_dbus_op_complete_t)(void *data);
@@ -390,12 +375,60 @@ fail:
return;
}
+static int parse_options(DBusMessageIter *iter, uint16_t *offset)
+{
+ DBusMessageIter dict;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+ return -EINVAL;
+
+ dbus_message_iter_recurse(iter, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ const char *key;
+ DBusMessageIter value, entry;
+ int var;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ var = dbus_message_iter_get_arg_type(&value);
+ if (strcasecmp(key, "offset") == 0) {
+ if (var != DBUS_TYPE_UINT16)
+ return -EINVAL;
+ dbus_message_iter_get_basic(&value, offset);
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int read_value(struct bt_gatt_client *gatt, uint16_t handle,
+ bt_gatt_client_read_callback_t callback,
+ struct async_dbus_op *op)
+{
+ if (op->offset)
+ return bt_gatt_client_read_long_value(gatt, handle, op->offset,
+ callback,
+ async_dbus_op_ref(op),
+ async_dbus_op_unref);
+ else
+ return bt_gatt_client_read_value(gatt, handle, callback,
+ async_dbus_op_ref(op),
+ async_dbus_op_unref);
+}
+
static DBusMessage *descriptor_read_value(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct descriptor *desc = user_data;
struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
+ DBusMessageIter iter;
struct async_dbus_op *op;
+ uint16_t offset = 0;
if (!gatt)
return btd_error_failed(msg, "Not connected");
@@ -403,14 +436,17 @@ static DBusMessage *descriptor_read_value(DBusConnection *conn,
if (desc->read_id)
return btd_error_in_progress(msg);
+ dbus_message_iter_init(msg, &iter);
+
+ if (parse_options(&iter, &offset))
+ return btd_error_invalid_args(msg);
+
op = new0(struct async_dbus_op, 1);
op->msg = dbus_message_ref(msg);
op->data = desc;
+ op->offset = offset;
- desc->read_id = bt_gatt_client_read_value(gatt, desc->handle,
- desc_read_cb,
- async_dbus_op_ref(op),
- async_dbus_op_unref);
+ desc->read_id = read_value(gatt, desc->handle, desc_read_cb, op);
if (desc->read_id)
return NULL;
@@ -450,7 +486,6 @@ done:
g_dbus_send_message(btd_get_dbus_connection(), reply);
}
-
static void write_cb(bool success, uint8_t att_ecode, void *user_data)
{
write_result_cb(success, false, att_ecode, user_data);
@@ -459,7 +494,8 @@ static void write_cb(bool success, uint8_t att_ecode, void *user_data)
static unsigned int start_long_write(DBusMessage *msg, uint16_t handle,
struct bt_gatt_client *gatt,
bool reliable, const uint8_t *value,
- size_t value_len, void *data,
+ size_t value_len, uint16_t offset,
+ void *data,
async_dbus_op_complete_t complete)
{
struct async_dbus_op *op;
@@ -469,9 +505,10 @@ static unsigned int start_long_write(DBusMessage *msg, uint16_t handle,
op->msg = dbus_message_ref(msg);
op->data = data;
op->complete = complete;
+ op->offset = offset;
- id = bt_gatt_client_write_long_value(gatt, reliable, handle,
- 0, value, value_len,
+ id = bt_gatt_client_write_long_value(gatt, reliable, handle, offset,
+ value, value_len,
write_result_cb, op,
async_dbus_op_free);
@@ -522,8 +559,10 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn,
{
struct descriptor *desc = user_data;
struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
+ DBusMessageIter iter;
uint8_t *value = NULL;
- size_t value_len = 0;
+ int value_len = 0;
+ uint16_t offset = 0;
if (!gatt)
return btd_error_failed(msg, "Not connected");
@@ -531,7 +570,12 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn,
if (desc->write_id)
return btd_error_in_progress(msg);
- if (!parse_value_arg(msg, &value, &value_len))
+ dbus_message_iter_init(msg, &iter);
+
+ if (parse_value_arg(&iter, &value, &value_len))
+ return btd_error_invalid_args(msg);
+
+ if (parse_options(&iter, &offset))
return btd_error_invalid_args(msg);
/*
@@ -546,15 +590,15 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn,
* Based on the value length and the MTU, either use a write or a long
* write.
*/
- if (value_len <= (unsigned) bt_gatt_client_get_mtu(gatt) - 3)
+ if (value_len <= bt_gatt_client_get_mtu(gatt) - 3 && !offset)
desc->write_id = start_write_request(msg, desc->handle,
gatt, value,
value_len, desc,
desc_write_complete);
else
- desc->write_id = start_long_write(msg, desc->handle,
- gatt, false, value,
- value_len, desc,
+ desc->write_id = start_long_write(msg, desc->handle, gatt,
+ false, value,
+ value_len, offset, desc,
desc_write_complete);
if (!desc->write_id)
@@ -574,13 +618,15 @@ static const GDBusPropertyTable descriptor_properties[] = {
};
static const GDBusMethodTable descriptor_methods[] = {
- { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue", NULL,
- GDBUS_ARGS({ "value", "ay" }),
- descriptor_read_value) },
+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue",
+ GDBUS_ARGS({ "options", "a{sv}" }),
+ GDBUS_ARGS({ "value", "ay" }),
+ descriptor_read_value) },
{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("WriteValue",
- GDBUS_ARGS({ "value", "ay" }),
- NULL,
- descriptor_write_value) },
+ GDBUS_ARGS({ "value", "ay" },
+ { "options", "a{sv}" }),
+ NULL,
+ descriptor_write_value) },
{ }
};
@@ -837,7 +883,9 @@ static DBusMessage *characteristic_read_value(DBusConnection *conn,
{
struct characteristic *chrc = user_data;
struct bt_gatt_client *gatt = chrc->service->client->gatt;
+ DBusMessageIter iter;
struct async_dbus_op *op;
+ uint16_t offset = 0;
if (!gatt)
return btd_error_failed(msg, "Not connected");
@@ -845,14 +893,17 @@ static DBusMessage *characteristic_read_value(DBusConnection *conn,
if (chrc->read_id)
return btd_error_in_progress(msg);
+ dbus_message_iter_init(msg, &iter);
+
+ if (parse_options(&iter, &offset))
+ return btd_error_invalid_args(msg);
+
op = new0(struct async_dbus_op, 1);
op->msg = dbus_message_ref(msg);
op->data = chrc;
+ op->offset = offset;
- chrc->read_id = bt_gatt_client_read_value(gatt, chrc->value_handle,
- chrc_read_cb,
- async_dbus_op_ref(op),
- async_dbus_op_unref);
+ chrc->read_id = read_value(gatt, chrc->value_handle, chrc_read_cb, op);
if (chrc->read_id)
return NULL;
@@ -879,9 +930,11 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
{
struct characteristic *chrc = user_data;
struct bt_gatt_client *gatt = chrc->service->client->gatt;
+ DBusMessageIter iter;
uint8_t *value = NULL;
- size_t value_len = 0;
+ int value_len = 0;
bool supported = false;
+ uint16_t offset = 0;
if (!gatt)
return btd_error_failed(msg, "Not connected");
@@ -889,7 +942,12 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
if (chrc->write_id)
return btd_error_in_progress(msg);
- if (!parse_value_arg(msg, &value, &value_len))
+ dbus_message_iter_init(msg, &iter);
+
+ if (parse_value_arg(&iter, &value, &value_len))
+ return btd_error_invalid_args(msg);
+
+ if (parse_options(&iter, &offset))
return btd_error_invalid_args(msg);
/*
@@ -906,7 +964,7 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
if ((chrc->ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE)) {
supported = true;
chrc->write_id = start_long_write(msg, chrc->value_handle, gatt,
- true, value, value_len,
+ true, value, value_len, offset,
chrc, chrc_write_complete);
if (chrc->write_id)
return NULL;
@@ -920,7 +978,7 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
if (!mtu)
return btd_error_failed(msg, "No ATT transport");
- if (value_len <= (unsigned) mtu - 3)
+ if (value_len <= mtu - 3 && !offset)
chrc->write_id = start_write_request(msg,
chrc->value_handle,
gatt, value, value_len,
@@ -928,7 +986,7 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
else
chrc->write_id = start_long_write(msg,
chrc->value_handle, gatt,
- false, value, value_len,
+ false, value, value_len, offset,
chrc, chrc_write_complete);
if (chrc->write_id)
@@ -1242,17 +1300,19 @@ static const GDBusPropertyTable characteristic_properties[] = {
};
static const GDBusMethodTable characteristic_methods[] = {
- { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue", NULL,
- GDBUS_ARGS({ "value", "ay" }),
- characteristic_read_value) },
+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue",
+ GDBUS_ARGS({ "options", "a{sv}" }),
+ GDBUS_ARGS({ "value", "ay" }),
+ characteristic_read_value) },
{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("WriteValue",
- GDBUS_ARGS({ "value", "ay" }),
- NULL,
- characteristic_write_value) },
+ GDBUS_ARGS({ "value", "ay" },
+ { "options", "a{sv}" }),
+ NULL,
+ characteristic_write_value) },
{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("StartNotify", NULL, NULL,
- characteristic_start_notify) },
+ characteristic_start_notify) },
{ GDBUS_EXPERIMENTAL_METHOD("StopNotify", NULL, NULL,
- characteristic_stop_notify) },
+ characteristic_stop_notify) },
{ }
};
diff --git a/src/gatt-database.c b/src/gatt-database.c
index b8da955..99d084d 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -135,6 +135,7 @@ struct external_desc {
};
struct pending_op {
+ struct btd_device *device;
unsigned int id;
struct gatt_db_attribute *attrib;
struct queue *owner_queue;
@@ -1592,7 +1593,8 @@ static void pending_op_free(void *data)
free(op);
}
-static struct pending_op *pending_read_new(struct queue *owner_queue,
+static struct pending_op *pending_read_new(struct btd_device *device,
+ struct queue *owner_queue,
struct gatt_db_attribute *attrib,
unsigned int id)
{
@@ -1601,6 +1603,7 @@ static struct pending_op *pending_read_new(struct queue *owner_queue,
op = new0(struct pending_op, 1);
op->owner_queue = owner_queue;
+ op->device = device;
op->attrib = attrib;
op->id = id;
queue_push_tail(owner_queue, op);
@@ -1608,33 +1611,75 @@ static struct pending_op *pending_read_new(struct queue *owner_queue,
return op;
}
-static void send_read(struct gatt_db_attribute *attrib, GDBusProxy *proxy,
- struct queue *owner_queue,
- unsigned int id)
+static void append_options(DBusMessageIter *iter, void *user_data)
+{
+ struct pending_op *op = user_data;
+ const char *path = device_get_path(op->device);
+
+ dict_append_entry(iter, "device", DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static void read_setup_cb(DBusMessageIter *iter, void *user_data)
+{
+ struct pending_op *op = user_data;
+ DBusMessageIter dict;
+
+ 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);
+
+ append_options(&dict, op);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+static struct pending_op *send_read(struct btd_device *device,
+ struct gatt_db_attribute *attrib,
+ GDBusProxy *proxy,
+ struct queue *owner_queue,
+ unsigned int id)
{
struct pending_op *op;
- uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
- op = pending_read_new(owner_queue, attrib, id);
+ op = pending_read_new(device, owner_queue, attrib, id);
- if (g_dbus_proxy_method_call(proxy, "ReadValue", NULL, read_reply_cb,
- op, pending_op_free) == TRUE)
- return;
+ if (g_dbus_proxy_method_call(proxy, "ReadValue", read_setup_cb,
+ read_reply_cb, op, pending_op_free) == TRUE)
+ return op;
pending_op_free(op);
- gatt_db_attribute_read_result(attrib, id, ecode, NULL, 0);
+ return NULL;
}
static void write_setup_cb(DBusMessageIter *iter, void *user_data)
{
struct pending_op *op = user_data;
- DBusMessageIter array;
+ DBusMessageIter array, dict;
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
&op->data.iov_base, op->data.iov_len);
dbus_message_iter_close_container(iter, &array);
+
+ 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);
+
+ append_options(&dict, op);
+
+ dbus_message_iter_close_container(iter, &dict);
+
+ if (!op->owner_queue) {
+ gatt_db_attribute_write_result(op->attrib, op->id, 0);
+ pending_op_free(op);
+ }
}
static void write_reply_cb(DBusMessage *message, void *user_data)
@@ -1673,7 +1718,8 @@ done:
gatt_db_attribute_write_result(op->attrib, op->id, ecode);
}
-static struct pending_op *pending_write_new(struct queue *owner_queue,
+static struct pending_op *pending_write_new(struct btd_device *device,
+ struct queue *owner_queue,
struct gatt_db_attribute *attrib,
unsigned int id,
const uint8_t *value,
@@ -1686,6 +1732,7 @@ static struct pending_op *pending_write_new(struct queue *owner_queue,
op->data.iov_base = (uint8_t *) value;
op->data.iov_len = len;
+ op->device = device;
op->owner_queue = owner_queue;
op->attrib = attrib;
op->id = id;
@@ -1694,24 +1741,25 @@ static struct pending_op *pending_write_new(struct queue *owner_queue,
return op;
}
-static void send_write(struct gatt_db_attribute *attrib, GDBusProxy *proxy,
+static struct pending_op *send_write(struct btd_device *device,
+ struct gatt_db_attribute *attrib,
+ GDBusProxy *proxy,
struct queue *owner_queue,
unsigned int id,
const uint8_t *value, size_t len)
{
struct pending_op *op;
- uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
- op = pending_write_new(owner_queue, attrib, id, value, len);
+ op = pending_write_new(device, owner_queue, attrib, id, value, len);
if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup_cb,
- write_reply_cb, op,
- pending_op_free) == TRUE)
- return;
+ owner_queue ? write_reply_cb : NULL,
+ op, pending_op_free) == TRUE)
+ return op;
pending_op_free(op);
- gatt_db_attribute_write_result(attrib, id, ecode);
+ return NULL;
}
static uint32_t permissions_from_props(uint8_t props, uint8_t ext_props)
@@ -1895,19 +1943,65 @@ static bool database_add_cep(struct external_service *service,
return true;
}
+static struct btd_device *att_get_device(struct bt_att *att)
+{
+ GIOChannel *io = NULL;
+ GError *gerr = NULL;
+ bdaddr_t src, dst;
+ uint8_t dst_type;
+ struct btd_adapter *adapter;
+
+ io = g_io_channel_unix_new(bt_att_get_fd(att));
+ if (!io)
+ return NULL;
+
+ bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_DEST_TYPE, &dst_type,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("bt_io_get: %s", gerr->message);
+ g_error_free(gerr);
+ g_io_channel_unref(io);
+ return NULL;
+ }
+
+ g_io_channel_unref(io);
+
+ adapter = adapter_find(&src);
+ if (!adapter) {
+ error("Unable to find adapter object");
+ return NULL;
+ }
+
+ return btd_adapter_find_device(adapter, &dst, dst_type);
+}
+
static void desc_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct external_desc *desc = user_data;
+ struct btd_device *device;
if (desc->attrib != attrib) {
error("Read callback called with incorrect attribute");
- return;
+ goto fail;
}
- send_read(attrib, desc->proxy, desc->pending_reads, id);
+ device = att_get_device(att);
+ if (!device) {
+ error("Unable to find device object");
+ goto fail;
+ }
+
+ if (send_read(device, attrib, desc->proxy, desc->pending_reads, id))
+ return;
+
+fail:
+ gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY,
+ NULL, 0);
}
static void desc_write_cb(struct gatt_db_attribute *attrib,
@@ -1917,13 +2011,26 @@ static void desc_write_cb(struct gatt_db_attribute *attrib,
void *user_data)
{
struct external_desc *desc = user_data;
+ struct btd_device *device;
if (desc->attrib != attrib) {
error("Read callback called with incorrect attribute");
- return;
+ goto fail;
}
- send_write(attrib, desc->proxy, desc->pending_writes, id, value, len);
+ device = att_get_device(att);
+ if (!device) {
+ error("Unable to find device object");
+ goto fail;
+ }
+
+ if (send_write(device, attrib, desc->proxy, desc->pending_writes, id,
+ value, len))
+ return;
+
+fail:
+ gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY,
+ NULL, 0);
}
static bool database_add_desc(struct external_service *service,
@@ -1956,43 +2063,25 @@ static void chrc_read_cb(struct gatt_db_attribute *attrib,
void *user_data)
{
struct external_chrc *chrc = user_data;
+ struct btd_device *device;
if (chrc->attrib != attrib) {
error("Read callback called with incorrect attribute");
- return;
+ goto fail;
}
- send_read(attrib, chrc->proxy, chrc->pending_reads, id);
-}
-
-static void write_without_response_setup_cb(DBusMessageIter *iter,
- void *user_data)
-{
- struct iovec *iov = user_data;
- DBusMessageIter array;
-
- dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
- dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
- &iov->iov_base, iov->iov_len);
- dbus_message_iter_close_container(iter, &array);
-}
-
-static void send_write_without_response(struct gatt_db_attribute *attrib,
- GDBusProxy *proxy, unsigned int id,
- const uint8_t *value, size_t len)
-{
- struct iovec iov;
- uint8_t ecode = 0;
-
- iov.iov_base = (uint8_t *) value;
- iov.iov_len = len;
+ device = att_get_device(att);
+ if (!device) {
+ error("Unable to find device object");
+ goto fail;
+ }
- if (!g_dbus_proxy_method_call(proxy, "WriteValue",
- write_without_response_setup_cb,
- NULL, &iov, NULL))
- ecode = BT_ATT_ERROR_UNLIKELY;
+ if (send_read(device, attrib, chrc->proxy, chrc->pending_reads, id))
+ return;
- gatt_db_attribute_write_result(attrib, id, ecode);
+fail:
+ gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY,
+ NULL, 0);
}
static void chrc_write_cb(struct gatt_db_attribute *attrib,
@@ -2002,19 +2091,31 @@ static void chrc_write_cb(struct gatt_db_attribute *attrib,
void *user_data)
{
struct external_chrc *chrc = user_data;
+ struct btd_device *device;
+ struct queue *queue;
if (chrc->attrib != attrib) {
error("Write callback called with incorrect attribute");
- return;
+ goto fail;
}
- if (chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) {
- send_write_without_response(attrib, chrc->proxy, id, value,
- len);
- return;
+ device = att_get_device(att);
+ if (!device) {
+ error("Unable to find device object");
+ goto fail;
}
- send_write(attrib, chrc->proxy, chrc->pending_writes, id, value, len);
+ if (!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP))
+ queue = chrc->pending_writes;
+ else
+ queue = NULL;
+
+ if (send_write(device, attrib, chrc->proxy, queue, id, value, len))
+ return;
+
+fail:
+ gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY,
+ NULL, 0);
}
static bool database_add_chrc(struct external_service *service,
--
2.5.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCHv2 BlueZ 2/6] doc/gatt-api: Merge RegisterProfile with RegisterApplication 2016-05-09 13:51 [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue Luiz Augusto von Dentz @ 2016-05-09 13:51 ` Luiz Augusto von Dentz 2016-05-09 13:51 ` [PATCHv2 BlueZ 3/6] doc/gatt-api: Add secure flags Luiz Augusto von Dentz ` (5 subsequent siblings) 6 siblings, 0 replies; 13+ messages in thread From: Luiz Augusto von Dentz @ 2016-05-09 13:51 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Since RegisterApplication makes use of ObjectManager it is also possible to verify the existance of GattProfile objects unifying the API for both services (GATT server) and profiles (GATT client). --- doc/gatt-api.txt | 37 ++--- src/gatt-database.c | 413 +++++++++++++++++++++------------------------------- 2 files changed, 171 insertions(+), 279 deletions(-) diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt index 683b1b7..9404986 100644 --- a/doc/gatt-api.txt +++ b/doc/gatt-api.txt @@ -218,8 +218,8 @@ Properties string UUID [read-only] "encrypt-authenticated-read" "encrypt-authenticated-write" -Profile hierarcy -================ +GATT Profile hierarcy +===================== Local profile (GATT client) instance. By registering this type of object an application effectively indicates support for a specific GATT profile @@ -238,6 +238,10 @@ Methods void Release() profile, because when this method gets called it has already been unregistered. +Properties array{string} UUIDs [read-only] + + 128-bit GATT service UUIDs. + GATT Manager hierarchy ====================== @@ -306,11 +310,12 @@ Object path [variable prefix]/{hci0,hci1,...} Methods void RegisterApplication(object application, dict options) Registers a local GATT services hierarchy as described - above. + above (GATT Server) and/or GATT profiles (GATT Client). The application object path together with the D-Bus system bus connection ID define the identification of - the application registering a GATT based service. + the application registering a GATT based + service or profile. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.AlreadyExists @@ -324,27 +329,3 @@ Methods void RegisterApplication(object application, dict options) Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.DoesNotExist - - void RegisterProfile(object profile, array{string} UUIDs, - dict options) - - Registers a GATT (client role) profile exported - under interface GattProfile1. The array of UUIDs - specifies the mandatory set of remote service - UUIDs that should all be available for the - remote device to match this profile. Matching - devices will be added to the auto-connection - list and connected whenever available. - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.AlreadyExists - - void UnregisterProfile(object profile) - - This unregisters the profile that has been - previously registered. The object path parameter - must match the same value that has been used - on registration. - - Possible errors: org.bluez.Error.InvalidArguments - org.bluez.Error.DoesNotExist diff --git a/src/gatt-database.c b/src/gatt-database.c index 99d084d..09bec0b 100644 --- a/src/gatt-database.c +++ b/src/gatt-database.c @@ -54,6 +54,7 @@ #endif #define GATT_MANAGER_IFACE "org.bluez.GattManager1" +#define GATT_PROFILE_IFACE "org.bluez.GattProfile1" #define GATT_SERVICE_IFACE "org.bluez.GattService1" #define GATT_CHRC_IFACE "org.bluez.GattCharacteristic1" #define GATT_DESC_IFACE "org.bluez.GattDescriptor1" @@ -88,6 +89,7 @@ struct gatt_app { DBusMessage *reg; GDBusClient *client; bool failed; + struct queue *profiles; struct queue *services; struct queue *proxies; }; @@ -103,10 +105,8 @@ struct external_service { }; struct external_profile { - struct btd_gatt_database *database; - char *owner; - char *path; /* Path to GattProfile1 */ - unsigned int id; + struct gatt_app *app; + GDBusProxy *proxy; struct queue *profiles; /* btd_profile list */ }; @@ -362,30 +362,6 @@ static void service_free(void *data) free(service); } -static void app_free(void *data) -{ - struct gatt_app *app = data; - - queue_destroy(app->services, service_free); - queue_destroy(app->proxies, NULL); - - if (app->client) { - g_dbus_client_set_disconnect_watch(app->client, NULL, NULL); - g_dbus_client_set_proxy_handlers(app->client, NULL, NULL, - NULL, NULL); - g_dbus_client_set_ready_watch(app->client, NULL, NULL); - g_dbus_client_unref(app->client); - } - - if (app->reg) - dbus_message_unref(app->reg); - - g_free(app->owner); - g_free(app->path); - - free(app); -} - static void profile_remove(void *data) { struct btd_profile *p = data; @@ -403,20 +379,10 @@ static void profile_remove(void *data) static void profile_release(struct external_profile *profile) { - DBusMessage *msg; - - if (!profile->id) - return; - - DBG("Releasing \"%s\"", profile->owner); - - g_dbus_remove_watch(btd_get_dbus_connection(), profile->id); + DBG("Releasing \"%s\"", profile->app->owner); - msg = dbus_message_new_method_call(profile->owner, profile->path, - "org.bluez.GattProfile1", - "Release"); - if (msg) - g_dbus_send_message(btd_get_dbus_connection(), msg); + g_dbus_proxy_method_call(profile->proxy, "Release", NULL, NULL, NULL, + NULL); } static void profile_free(void *data) @@ -427,12 +393,36 @@ static void profile_free(void *data) profile_release(profile); - g_free(profile->owner); - g_free(profile->path); + g_dbus_proxy_unref(profile->proxy); free(profile); } +static void app_free(void *data) +{ + struct gatt_app *app = data; + + queue_destroy(app->profiles, profile_free); + queue_destroy(app->services, service_free); + queue_destroy(app->proxies, NULL); + + if (app->client) { + g_dbus_client_set_disconnect_watch(app->client, NULL, NULL); + g_dbus_client_set_proxy_handlers(app->client, NULL, NULL, + NULL, NULL); + g_dbus_client_set_ready_watch(app->client, NULL, NULL); + g_dbus_client_unref(app->client); + } + + if (app->reg) + dbus_message_unref(app->reg); + + g_free(app->owner); + g_free(app->path); + + free(app); +} + static void gatt_database_free(void *data) { struct btd_gatt_database *database = data; @@ -2235,9 +2225,6 @@ static bool database_add_app(struct gatt_app *app) { const struct queue_entry *entry; - if (queue_isempty(app->services)) - return false; - entry = queue_get_entries(app->services); while (entry) { if (!database_add_service(entry->data)) { @@ -2251,6 +2238,131 @@ static bool database_add_app(struct gatt_app *app) return true; } +static int profile_device_probe(struct btd_service *service) +{ + struct btd_profile *p = btd_service_get_profile(service); + + DBG("%s probed", p->name); + + return 0; +} + +static void profile_device_remove(struct btd_service *service) +{ + struct btd_profile *p = btd_service_get_profile(service); + + DBG("%s removed", p->name); +} + +static int profile_add(struct external_profile *profile, const char *uuid) +{ + struct btd_profile *p; + + p = new0(struct btd_profile, 1); + + /* Assign directly to avoid having extra fields */ + p->name = (const void *) g_strdup_printf("%s%s/%s", profile->app->owner, + g_dbus_proxy_get_path(profile->proxy), uuid); + if (!p->name) { + free(p); + return -ENOMEM; + } + + p->remote_uuid = (const void *) g_strdup(uuid); + if (!p->remote_uuid) { + g_free((void *) p->name); + free(p); + return -ENOMEM; + } + + p->device_probe = profile_device_probe; + p->device_remove = profile_device_remove; + p->auto_connect = true; + p->external = true; + + queue_push_tail(profile->profiles, p); + + DBG("Added \"%s\"", p->name); + + return 0; +} + +static void add_profile(void *data, void *user_data) +{ + struct btd_adapter *adapter = user_data; + + btd_profile_register(data); + adapter_add_profile(adapter, data); +} + +static struct external_profile *create_profile(struct gatt_app *app, + GDBusProxy *proxy, + const char *path) +{ + struct external_profile *profile; + DBusMessageIter iter, array; + + if (!path || !g_str_has_prefix(path, "/")) + return NULL; + + profile = new0(struct external_profile, 1); + + profile->app = app; + profile->proxy = g_dbus_proxy_ref(proxy); + profile->profiles = queue_new(); + + if (!g_dbus_proxy_get_property(proxy, "UUIDs", &iter)) { + DBG("UUIDs property not found"); + goto fail; + } + + dbus_message_iter_recurse(&iter, &array); + + while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) { + const char *uuid; + + dbus_message_iter_get_basic(&array, &uuid); + + if (profile_add(profile, uuid) < 0) + goto fail; + + dbus_message_iter_next(&array); + } + + if (queue_isempty(profile->profiles)) + goto fail; + + queue_foreach(profile->profiles, add_profile, app->database->adapter); + queue_push_tail(app->profiles, profile); + + return profile; + +fail: + profile_free(profile); + return NULL; +} + +static void register_profile(void *data, void *user_data) +{ + struct gatt_app *app = user_data; + GDBusProxy *proxy = data; + const char *iface = g_dbus_proxy_get_interface(proxy); + const char *path = g_dbus_proxy_get_path(proxy); + + if (app->failed) + return; + + if (g_strcmp0(iface, GATT_PROFILE_IFACE) == 0) { + struct external_profile *profile; + + profile = create_profile(app, proxy, path); + if (!profile) { + app->failed = true; + return; + } + } +} + static void register_service(void *data, void *user_data) { struct gatt_app *app = user_data; @@ -2333,11 +2445,13 @@ static void client_ready_cb(GDBusClient *client, void *user_data) goto reply; } + queue_foreach(app->proxies, register_profile, app); queue_foreach(app->proxies, register_service, app); queue_foreach(app->proxies, register_characteristic, app); queue_foreach(app->proxies, register_descriptor, app); - if (!app->services || app->failed) { + if ((queue_isempty(app->services) && queue_isempty(app->profiles)) || + app->failed) { error("No valid external GATT objects found"); fail = true; reply = btd_error_failed(app->reg, @@ -2390,6 +2504,7 @@ static struct gatt_app *create_app(DBusConnection *conn, DBusMessage *msg, goto fail; app->services = queue_new(); + app->profiles = queue_new(); app->proxies = queue_new(); app->reg = dbus_message_ref(msg); @@ -2476,203 +2591,6 @@ static DBusMessage *manager_unregister_app(DBusConnection *conn, return dbus_message_new_method_return(msg); } -static void profile_exited(DBusConnection *conn, void *user_data) -{ - struct external_profile *profile = user_data; - - DBG("\"%s\" exited", profile->owner); - - profile->id = 0; - - queue_remove(profile->database->profiles, profile); - - profile_free(profile); -} - -static int profile_device_probe(struct btd_service *service) -{ - struct btd_profile *p = btd_service_get_profile(service); - - DBG("%s probed", p->name); - - return 0; -} - -static void profile_device_remove(struct btd_service *service) -{ - struct btd_profile *p = btd_service_get_profile(service); - - DBG("%s removed", p->name); -} - -static int profile_add(struct external_profile *profile, const char *uuid) -{ - struct btd_profile *p; - - p = new0(struct btd_profile, 1); - - /* Assign directly to avoid having extra fields */ - p->name = (const void *) g_strdup_printf("%s%s/%s", profile->owner, - profile->path, uuid); - if (!p->name) { - free(p); - return -ENOMEM; - } - - p->remote_uuid = (const void *) g_strdup(uuid); - if (!p->remote_uuid) { - g_free((void *) p->name); - free(p); - return -ENOMEM; - } - - p->device_probe = profile_device_probe; - p->device_remove = profile_device_remove; - p->auto_connect = true; - p->external = true; - - queue_push_tail(profile->profiles, p); - - DBG("Added \"%s\"", p->name); - - return 0; -} - -static void add_profile(void *data, void *user_data) -{ - struct btd_adapter *adapter = user_data; - - btd_profile_register(data); - adapter_add_profile(adapter, data); -} - -static int profile_create(DBusConnection *conn, - struct btd_gatt_database *database, - const char *sender, const char *path, - DBusMessageIter *iter) -{ - struct external_profile *profile; - DBusMessageIter uuids; - - if (!path || !g_str_has_prefix(path, "/")) - return -EINVAL; - - profile = new0(struct external_profile, 1); - - profile->owner = g_strdup(sender); - if (!profile->owner) - goto fail; - - profile->path = g_strdup(path); - if (!profile->path) - goto fail; - - profile->profiles = queue_new(); - profile->database = database; - profile->id = g_dbus_add_disconnect_watch(conn, sender, profile_exited, - profile, NULL); - - dbus_message_iter_recurse(iter, &uuids); - - while (dbus_message_iter_get_arg_type(&uuids) == DBUS_TYPE_STRING) { - const char *uuid; - - dbus_message_iter_get_basic(&uuids, &uuid); - - if (profile_add(profile, uuid) < 0) - goto fail; - - dbus_message_iter_next(&uuids); - } - - if (queue_isempty(profile->profiles)) - goto fail; - - queue_foreach(profile->profiles, add_profile, database->adapter); - queue_push_tail(database->profiles, profile); - - return 0; - -fail: - profile_free(profile); - return -EINVAL; -} - -static bool match_profile(const void *a, const void *b) -{ - const struct external_profile *profile = a; - const struct svc_match_data *data = b; - - return g_strcmp0(profile->path, data->path) == 0 && - g_strcmp0(profile->owner, data->sender) == 0; -} - -static DBusMessage *manager_register_profile(DBusConnection *conn, - DBusMessage *msg, void *user_data) -{ - struct btd_gatt_database *database = user_data; - const char *sender = dbus_message_get_sender(msg); - DBusMessageIter args; - const char *path; - struct svc_match_data match_data; - - DBG("sender %s", sender); - - if (!dbus_message_iter_init(msg, &args)) - return btd_error_invalid_args(msg); - - if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) - return btd_error_invalid_args(msg); - - dbus_message_iter_get_basic(&args, &path); - - match_data.path = path; - match_data.sender = sender; - - if (queue_find(database->profiles, match_profile, &match_data)) - return btd_error_already_exists(msg); - - dbus_message_iter_next(&args); - if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY) - return btd_error_invalid_args(msg); - - if (profile_create(conn, database, sender, path, &args) < 0) - return btd_error_failed(msg, "Failed to register profile"); - - return dbus_message_new_method_return(msg); -} - -static DBusMessage *manager_unregister_profile(DBusConnection *conn, - DBusMessage *msg, void *user_data) -{ - struct btd_gatt_database *database = user_data; - const char *sender = dbus_message_get_sender(msg); - const char *path; - DBusMessageIter args; - struct external_profile *profile; - struct svc_match_data match_data; - - if (!dbus_message_iter_init(msg, &args)) - return btd_error_invalid_args(msg); - - if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) - return btd_error_invalid_args(msg); - - dbus_message_iter_get_basic(&args, &path); - - match_data.path = path; - match_data.sender = sender; - - profile = queue_remove_if(database->profiles, match_profile, - &match_data); - if (!profile) - return btd_error_does_not_exist(msg); - - profile_free(profile); - - return dbus_message_new_method_return(msg); -} - static const GDBusMethodTable manager_methods[] = { { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterApplication", GDBUS_ARGS({ "application", "o" }, @@ -2681,13 +2599,6 @@ static const GDBusMethodTable manager_methods[] = { { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterApplication", GDBUS_ARGS({ "application", "o" }), NULL, manager_unregister_app) }, - { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterProfile", - GDBUS_ARGS({ "profile", "o" }, { "UUIDs", "as" }, - { "options", "a{sv}" }), NULL, - manager_register_profile) }, - { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterProfile", - GDBUS_ARGS({ "profile", "o" }), - NULL, manager_unregister_profile) }, { } }; -- 2.5.5 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCHv2 BlueZ 3/6] doc/gatt-api: Add secure flags 2016-05-09 13:51 [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue Luiz Augusto von Dentz 2016-05-09 13:51 ` [PATCHv2 BlueZ 2/6] doc/gatt-api: Merge RegisterProfile with RegisterApplication Luiz Augusto von Dentz @ 2016-05-09 13:51 ` Luiz Augusto von Dentz 2016-05-09 13:51 ` [PATCHv2 BlueZ 4/6] test: Update GATT examples with the new API Luiz Augusto von Dentz ` (4 subsequent siblings) 6 siblings, 0 replies; 13+ messages in thread From: Luiz Augusto von Dentz @ 2016-05-09 13:51 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> This add secure-{read,write} which shall be used by servers that want to restrict attribute access to secure connection only (BT_SECURITY_FIPS) --- doc/gatt-api.txt | 4 +++ lib/bluetooth.h | 1 + src/gatt-database.c | 90 ++++++++++++++++++++---------------------------- src/shared/att-types.h | 5 +++ src/shared/gatt-server.c | 3 ++ 5 files changed, 51 insertions(+), 52 deletions(-) diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt index 9404986..cb4e196 100644 --- a/doc/gatt-api.txt +++ b/doc/gatt-api.txt @@ -150,6 +150,8 @@ Properties string UUID [read-only] "encrypt-write" "encrypt-authenticated-read" "encrypt-authenticated-write" + "secure-read" (Server only) + "secure-write" (Server only) Characteristic Descriptors hierarchy ==================================== @@ -217,6 +219,8 @@ Properties string UUID [read-only] "encrypt-write" "encrypt-authenticated-read" "encrypt-authenticated-write" + "secure-read" (Server Only) + "secure-write" (Server Only) GATT Profile hierarcy ===================== diff --git a/lib/bluetooth.h b/lib/bluetooth.h index 852a6b2..eb27926 100644 --- a/lib/bluetooth.h +++ b/lib/bluetooth.h @@ -69,6 +69,7 @@ struct bt_security { #define BT_SECURITY_LOW 1 #define BT_SECURITY_MEDIUM 2 #define BT_SECURITY_HIGH 3 +#define BT_SECURITY_FIPS 4 #define BT_DEFER_SETUP 7 diff --git a/src/gatt-database.c b/src/gatt-database.c index 09bec0b..e287b98 100644 --- a/src/gatt-database.c +++ b/src/gatt-database.c @@ -116,6 +116,7 @@ struct external_chrc { GDBusProxy *proxy; uint8_t props; uint8_t ext_props; + uint32_t perm; struct gatt_db_attribute *attrib; struct gatt_db_attribute *ccc; struct queue *pending_reads; @@ -1113,7 +1114,7 @@ static bool incr_attr_count(struct external_service *service, uint16_t incr) } static bool parse_chrc_flags(DBusMessageIter *array, uint8_t *props, - uint8_t *ext_props) + uint8_t *ext_props, uint32_t *perm) { const char *flag; @@ -1127,34 +1128,51 @@ static bool parse_chrc_flags(DBusMessageIter *array, uint8_t *props, if (!strcmp("broadcast", flag)) *props |= BT_GATT_CHRC_PROP_BROADCAST; - else if (!strcmp("read", flag)) + else if (!strcmp("read", flag)) { *props |= BT_GATT_CHRC_PROP_READ; - else if (!strcmp("write-without-response", flag)) + *perm |= BT_ATT_PERM_READ; + } else if (!strcmp("write-without-response", flag)) { *props |= BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP; - else if (!strcmp("write", flag)) + *perm |= BT_ATT_PERM_WRITE; + } else if (!strcmp("write", flag)) { *props |= BT_GATT_CHRC_PROP_WRITE; - else if (!strcmp("notify", flag)) + *perm |= BT_ATT_PERM_WRITE; + } else if (!strcmp("notify", flag)) { *props |= BT_GATT_CHRC_PROP_NOTIFY; - else if (!strcmp("indicate", flag)) + } else if (!strcmp("indicate", flag)) { *props |= BT_GATT_CHRC_PROP_INDICATE; - else if (!strcmp("authenticated-signed-writes", flag)) + } else if (!strcmp("authenticated-signed-writes", flag)) { *props |= BT_GATT_CHRC_PROP_AUTH; - else if (!strcmp("reliable-write", flag)) + *perm |= BT_ATT_PERM_WRITE; + } else if (!strcmp("reliable-write", flag)) { *ext_props |= BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE; - else if (!strcmp("writable-auxiliaries", flag)) + *perm |= BT_ATT_PERM_WRITE; + } else if (!strcmp("writable-auxiliaries", flag)) { *ext_props |= BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX; - else if (!strcmp("encrypt-read", flag)) { + } else if (!strcmp("encrypt-read", flag)) { *props |= BT_GATT_CHRC_PROP_READ; *ext_props |= BT_GATT_CHRC_EXT_PROP_ENC_READ; + *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_ENCRYPT; } else if (!strcmp("encrypt-write", flag)) { *props |= BT_GATT_CHRC_PROP_WRITE; *ext_props |= BT_GATT_CHRC_EXT_PROP_ENC_WRITE; + *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_ENCRYPT; } else if (!strcmp("encrypt-authenticated-read", flag)) { *props |= BT_GATT_CHRC_PROP_READ; *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_READ; + *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN; } else if (!strcmp("encrypt-authenticated-write", flag)) { *props |= BT_GATT_CHRC_PROP_WRITE; *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_WRITE; + *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN; + } else if (!strcmp("secure-read", flag)) { + *props |= BT_GATT_CHRC_PROP_READ; + *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_READ; + *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_READ_SECURE; + } else if (!strcmp("secure-write", flag)) { + *props |= BT_GATT_CHRC_PROP_WRITE; + *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_WRITE; + *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_SECURE; } else { error("Invalid characteristic flag: %s", flag); return false; @@ -1191,6 +1209,10 @@ static bool parse_desc_flags(DBusMessageIter *array, uint32_t *perm) *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN; else if (!strcmp("encrypt-authenticated-write", flag)) *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN; + else if (!strcmp("secure-read", flag)) + *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN; + else if (!strcmp("secure-write", flag)) + *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN; else { error("Invalid descriptor flag: %s", flag); return false; @@ -1204,6 +1226,7 @@ static bool parse_flags(GDBusProxy *proxy, uint8_t *props, uint8_t *ext_props, uint32_t *perm) { DBusMessageIter iter, array; + const char *iface; if (!g_dbus_proxy_get_property(proxy, "Flags", &iter)) return false; @@ -1213,10 +1236,11 @@ static bool parse_flags(GDBusProxy *proxy, uint8_t *props, uint8_t *ext_props, dbus_message_iter_recurse(&iter, &array); - if (perm) + iface = g_dbus_proxy_get_interface(proxy); + if (!strcmp(iface, GATT_DESC_IFACE)) return parse_desc_flags(&array, perm); - return parse_chrc_flags(&array, props, ext_props); + return parse_chrc_flags(&array, props, ext_props, perm); } static struct external_chrc *chrc_create(struct gatt_app *app, @@ -1264,7 +1288,7 @@ static struct external_chrc *chrc_create(struct gatt_app *app, * are used to determine if any special descriptors should be * created. */ - if (!parse_flags(proxy, &chrc->props, &chrc->ext_props, NULL)) { + if (!parse_flags(proxy, &chrc->props, &chrc->ext_props, &chrc->perm)) { error("Failed to parse characteristic properties"); goto fail; } @@ -1752,37 +1776,6 @@ static struct pending_op *send_write(struct btd_device *device, return NULL; } -static uint32_t permissions_from_props(uint8_t props, uint8_t ext_props) -{ - uint32_t perm = 0; - - if (props & BT_GATT_CHRC_PROP_WRITE || - props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP || - ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE || - ext_props & BT_GATT_CHRC_EXT_PROP_ENC_WRITE || - ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_WRITE) - perm |= BT_ATT_PERM_WRITE; - - if (props & BT_GATT_CHRC_PROP_READ || - ext_props & BT_GATT_CHRC_EXT_PROP_ENC_READ || - ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_READ) - perm |= BT_ATT_PERM_READ; - - if (ext_props & BT_GATT_CHRC_EXT_PROP_ENC_READ) - perm |= BT_ATT_PERM_READ_ENCRYPT; - - if (ext_props & BT_GATT_CHRC_EXT_PROP_ENC_WRITE) - perm |= BT_ATT_PERM_WRITE_ENCRYPT; - - if (ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_READ) - perm |= BT_ATT_PERM_READ_AUTHEN; - - if (ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_WRITE) - perm |= BT_ATT_PERM_WRITE_AUTHEN; - - return perm; -} - static uint8_t ccc_write_cb(uint16_t value, void *user_data) { struct external_chrc *chrc = user_data; @@ -2112,7 +2105,6 @@ static bool database_add_chrc(struct external_service *service, struct external_chrc *chrc) { bt_uuid_t uuid; - uint32_t perm; const struct queue_entry *entry; if (!parse_uuid(chrc->proxy, &uuid)) { @@ -2125,14 +2117,8 @@ static bool database_add_chrc(struct external_service *service, return false; } - /* - * TODO: Once shared/gatt-server properly supports permission checks, - * set the permissions based on a D-Bus property of the external - * characteristic. - */ - perm = permissions_from_props(chrc->props, chrc->ext_props); chrc->attrib = gatt_db_service_add_characteristic(service->attrib, - &uuid, perm, + &uuid, chrc->perm, chrc->props, chrc_read_cb, chrc_write_cb, chrc); if (!chrc->attrib) { diff --git a/src/shared/att-types.h b/src/shared/att-types.h index c3062c0..4a9b67f 100644 --- a/src/shared/att-types.h +++ b/src/shared/att-types.h @@ -31,6 +31,7 @@ #define BT_ATT_SECURITY_LOW 1 #define BT_ATT_SECURITY_MEDIUM 2 #define BT_ATT_SECURITY_HIGH 3 +#define BT_ATT_SECURITY_FIPS 4 #define BT_ATT_DEFAULT_LE_MTU 23 #define BT_ATT_MAX_LE_MTU 517 @@ -123,6 +124,10 @@ struct bt_att_pdu_error_rsp { BT_ATT_PERM_WRITE_AUTHEN) #define BT_ATT_PERM_AUTHOR 0x40 #define BT_ATT_PERM_NONE 0x80 +#define BT_ATT_PERM_READ_SECURE 0x0100 +#define BT_ATT_PERM_WRITE_SECURE 0x0200 +#define BT_ATT_PERM_SECURE (BT_ATT_PERM_READ_SECURE | \ + BT_ATT_PERM_WRITE_SECURE) /* GATT Characteristic Properties Bitfield values */ #define BT_GATT_CHRC_PROP_BROADCAST 0x01 diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c index 123d9c1..79e01c8 100644 --- a/src/shared/gatt-server.c +++ b/src/shared/gatt-server.c @@ -398,6 +398,9 @@ static uint8_t check_permissions(struct bt_gatt_server *server, return 0; security = bt_att_get_security(server->att); + if (perm & BT_ATT_PERM_SECURE && security < BT_ATT_SECURITY_FIPS) + return BT_ATT_ERROR_AUTHENTICATION; + if (perm & BT_ATT_PERM_AUTHEN && security < BT_ATT_SECURITY_HIGH) return BT_ATT_ERROR_AUTHENTICATION; -- 2.5.5 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCHv2 BlueZ 4/6] test: Update GATT examples with the new API 2016-05-09 13:51 [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue Luiz Augusto von Dentz 2016-05-09 13:51 ` [PATCHv2 BlueZ 2/6] doc/gatt-api: Merge RegisterProfile with RegisterApplication Luiz Augusto von Dentz 2016-05-09 13:51 ` [PATCHv2 BlueZ 3/6] doc/gatt-api: Add secure flags Luiz Augusto von Dentz @ 2016-05-09 13:51 ` Luiz Augusto von Dentz 2016-05-09 13:51 ` [PATCHv2 BlueZ 5/6] client: Update to use new GATT API Luiz Augusto von Dentz ` (3 subsequent siblings) 6 siblings, 0 replies; 13+ messages in thread From: Luiz Augusto von Dentz @ 2016-05-09 13:51 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> --- test/example-gatt-client | 2 +- test/example-gatt-server | 90 +++++++++++++++++++++++++------- test/test-gatt-profile | 130 ++++++++++++++++++++++++++++++++++++----------- 3 files changed, 172 insertions(+), 50 deletions(-) diff --git a/test/example-gatt-client b/test/example-gatt-client index b77a627..4d1df2f 100755 --- a/test/example-gatt-client +++ b/test/example-gatt-client @@ -113,7 +113,7 @@ def hr_msrmt_changed_cb(iface, changed_props, invalidated_props): def start_client(): # Read the Body Sensor Location value and print it asynchronously. - body_snsr_loc_chrc[0].ReadValue(reply_handler=body_sensor_val_cb, + body_snsr_loc_chrc[0].ReadValue({}, reply_handler=body_sensor_val_cb, error_handler=generic_error_cb, dbus_interface=GATT_CHRC_IFACE) diff --git a/test/example-gatt-server b/test/example-gatt-server index 93cf068..71aeb1b 100755 --- a/test/example-gatt-server +++ b/test/example-gatt-server @@ -166,13 +166,15 @@ class Characteristic(dbus.service.Object): return self.get_properties[GATT_CHRC_IFACE] - @dbus.service.method(GATT_CHRC_IFACE, out_signature='ay') - def ReadValue(self): + @dbus.service.method(GATT_CHRC_IFACE, + in_signature='a{sv}', + out_signature='ay') + def ReadValue(self, options): print('Default ReadValue called, returning error') raise NotSupportedException() - @dbus.service.method(GATT_CHRC_IFACE, in_signature='ay') - def WriteValue(self, value): + @dbus.service.method(GATT_CHRC_IFACE, in_signature='aya{sv}') + def WriteValue(self, value, options): print('Default WriteValue called, returning error') raise NotSupportedException() @@ -222,13 +224,15 @@ class Descriptor(dbus.service.Object): return self.get_properties[GATT_CHRC_IFACE] - @dbus.service.method(GATT_DESC_IFACE, out_signature='ay') - def ReadValue(self): + @dbus.service.method(GATT_DESC_IFACE, + in_signature='a{sv}', + out_signature='ay') + def ReadValue(self, options): print ('Default ReadValue called, returning error') raise NotSupportedException() - @dbus.service.method(GATT_DESC_IFACE, in_signature='ay') - def WriteValue(self, value): + @dbus.service.method(GATT_DESC_IFACE, in_signature='aya{sv}') + def WriteValue(self, value, options): print('Default WriteValue called, returning error') raise NotSupportedException() @@ -317,7 +321,7 @@ class BodySensorLocationChrc(Characteristic): ['read'], service) - def ReadValue(self): + def ReadValue(self, options): # Return 'Chest' as the sensor location. return [ 0x01 ] @@ -331,7 +335,7 @@ class HeartRateControlPointChrc(Characteristic): ['write'], service) - def WriteValue(self, value): + def WriteValue(self, value, options): print('Heart Rate Control Point WriteValue called') if len(value) != 1: @@ -393,7 +397,7 @@ class BatteryLevelCharacteristic(Characteristic): self.notify_battery_level() return True - def ReadValue(self): + def ReadValue(self, options): print('Battery Level read: ' + repr(self.battery_lvl)) return [dbus.Byte(self.battery_lvl)] @@ -425,6 +429,7 @@ class TestService(Service): Service.__init__(self, bus, index, self.TEST_SVC_UUID, False) self.add_characteristic(TestCharacteristic(bus, 0, self)) self.add_characteristic(TestEncryptCharacteristic(bus, 1, self)) + self.add_characteristic(TestSecureCharacteristic(bus, 2, self)) class TestCharacteristic(Characteristic): """ @@ -445,11 +450,11 @@ class TestCharacteristic(Characteristic): self.add_descriptor( CharacteristicUserDescriptionDescriptor(bus, 1, self)) - def ReadValue(self): + def ReadValue(self, options): print('TestCharacteristic Read: ' + repr(self.value)) return self.value - def WriteValue(self, value): + def WriteValue(self, value, options): print('TestCharacteristic Write: ' + repr(value)) self.value = value @@ -468,7 +473,7 @@ class TestDescriptor(Descriptor): ['read', 'write'], characteristic) - def ReadValue(self): + def ReadValue(self, options): return [ dbus.Byte('T'), dbus.Byte('e'), dbus.Byte('s'), dbus.Byte('t') ] @@ -491,10 +496,10 @@ class CharacteristicUserDescriptionDescriptor(Descriptor): ['read', 'write'], characteristic) - def ReadValue(self): + def ReadValue(self, options): return self.value - def WriteValue(self, value): + def WriteValue(self, value, options): if not self.writable: raise NotPermittedException() self.value = value @@ -517,11 +522,11 @@ class TestEncryptCharacteristic(Characteristic): self.add_descriptor( CharacteristicUserDescriptionDescriptor(bus, 3, self)) - def ReadValue(self): + def ReadValue(self, options): print('TestCharacteristic Read: ' + repr(self.value)) return self.value - def WriteValue(self, value): + def WriteValue(self, value, options): print('TestCharacteristic Write: ' + repr(value)) self.value = value @@ -539,7 +544,54 @@ class TestEncryptDescriptor(Descriptor): ['encrypt-read', 'encrypt-write'], characteristic) - def ReadValue(self): + def ReadValue(self, options): + return [ + dbus.Byte('T'), dbus.Byte('e'), dbus.Byte('s'), dbus.Byte('t') + ] + + +class TestSecureCharacteristic(Characteristic): + """ + Dummy test characteristic requiring secure connection. + + """ + TEST_CHRC_UUID = '12345678-1234-5678-1234-56789abcdef5' + + def __init__(self, bus, index, service): + Characteristic.__init__( + self, bus, index, + self.TEST_CHRC_UUID, + ['secure-read', 'secure-write'], + service) + self.value = [] + self.add_descriptor(TestEncryptDescriptor(bus, 2, self)) + self.add_descriptor( + CharacteristicUserDescriptionDescriptor(bus, 3, self)) + + def ReadValue(self, options): + print('TestCharacteristic Read: ' + repr(self.value)) + return self.value + + def WriteValue(self, value, options): + print('TestCharacteristic Write: ' + repr(value)) + self.value = value + + +class TestSecureDescriptor(Descriptor): + """ + Dummy test descriptor requiring secure connection. Returns a static value. + + """ + TEST_DESC_UUID = '12345678-1234-5678-1234-56789abcdef6' + + def __init__(self, bus, index, characteristic): + Descriptor.__init__( + self, bus, index, + self.TEST_DESC_UUID, + ['secure-read', 'secure-write'], + characteristic) + + def ReadValue(self, options): return [ dbus.Byte('T'), dbus.Byte('e'), dbus.Byte('s'), dbus.Byte('t') ] diff --git a/test/test-gatt-profile b/test/test-gatt-profile index ad320b1..995a659 100755 --- a/test/test-gatt-profile +++ b/test/test-gatt-profile @@ -15,46 +15,116 @@ except ImportError: import gobject as GObject import bluezutils -class GattProfile(dbus.service.Object): - @dbus.service.method("org.bluez.GattProfile1", - in_signature="", out_signature="") - def Release(self): - print("Release") - mainloop.quit() +BLUEZ_SERVICE_NAME = 'org.bluez' +GATT_MANAGER_IFACE = 'org.bluez.GattManager1' +DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager' +DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties' -if __name__ == '__main__': - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) +GATT_PROFILE_IFACE = 'org.bluez.GattProfile1' + + +class InvalidArgsException(dbus.exceptions.DBusException): + _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs' + + +class Application(dbus.service.Object): + def __init__(self, bus): + self.path = '/' + self.profiles = [] + dbus.service.Object.__init__(self, bus, self.path) + + def get_path(self): + return dbus.ObjectPath(self.path) + + def add_profile(self, profile): + self.profiles.append(profile) + + @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}') + def GetManagedObjects(self): + response = {} + print('GetManagedObjects') + + for profile in self.profiles: + response[profile.get_path()] = profile.get_properties() + + return response + + +class Profile(dbus.service.Object): + PATH_BASE = '/org/bluez/example/profile' - bus = dbus.SystemBus() + def __init__(self, bus, uuids): + self.path = self.PATH_BASE + self.bus = bus + self.uuids = uuids + dbus.service.Object.__init__(self, bus, self.path) + + def get_properties(self): + return { + GATT_PROFILE_IFACE: { + 'UUIDs': self.uuids, + } + } + + def get_path(self): + return dbus.ObjectPath(self.path) + + @dbus.service.method(GATT_PROFILE_IFACE, + in_signature="", + out_signature="") + def Release(self): + print("Release") + mainloop.quit() + + @dbus.service.method(DBUS_PROP_IFACE, + in_signature='s', + out_signature='a{sv}') + def GetAll(self, interface): + if interface != GATT_PROFILE_IFACE: + raise InvalidArgsException() + + return self.get_properties[GATT_PROFILE_IFACE] + + +def register_app_cb(): + print('GATT application registered') + + +def register_app_error_cb(error): + print('Failed to register application: ' + str(error)) + mainloop.quit() + +if __name__ == '__main__': + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - path = bluezutils.find_adapter().object_path + bus = dbus.SystemBus() - manager = dbus.Interface(bus.get_object("org.bluez", path), - "org.bluez.GattManager1") + path = bluezutils.find_adapter().object_path - option_list = [ - make_option("-u", "--uuid", action="store", - type="string", dest="uuid", - default=None), - make_option("-p", "--path", action="store", - type="string", dest="path", - default="/foo/bar/profile"), - ] + manager = dbus.Interface(bus.get_object("org.bluez", path), + GATT_MANAGER_IFACE) - opts = dbus.Dictionary({ }, signature='sv') + option_list = [make_option("-u", "--uuid", action="store", + type="string", dest="uuid", + default=None), + ] - parser = OptionParser(option_list=option_list) + opts = dbus.Dictionary({}, signature='sv') - (options, args) = parser.parse_args() + parser = OptionParser(option_list=option_list) - profile = GattProfile(bus, options.path) + (options, args) = parser.parse_args() - mainloop = GObject.MainLoop() + mainloop = GObject.MainLoop() - if not options.uuid: - options.uuid = str(uuid.uuid4()) + if not options.uuid: + options.uuid = str(uuid.uuid4()) - uuids = { options.uuid } - manager.RegisterProfile(options.path, uuids, opts) + app = Application(bus) + profile = Profile(bus, [options.uuid]) + app.add_profile(profile) + manager.RegisterApplication(app.get_path(), {}, + reply_handler=register_app_cb, + error_handler=register_app_error_cb) - mainloop.run() + mainloop.run() -- 2.5.5 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCHv2 BlueZ 5/6] client: Update to use new GATT API 2016-05-09 13:51 [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue Luiz Augusto von Dentz ` (2 preceding siblings ...) 2016-05-09 13:51 ` [PATCHv2 BlueZ 4/6] test: Update GATT examples with the new API Luiz Augusto von Dentz @ 2016-05-09 13:51 ` Luiz Augusto von Dentz 2016-05-09 13:51 ` [PATCHv2 BlueZ 6/6] tools/gatt-service: " Luiz Augusto von Dentz ` (2 subsequent siblings) 6 siblings, 0 replies; 13+ messages in thread From: Luiz Augusto von Dentz @ 2016-05-09 13:51 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> This update use of ReadValue and WriteValue to include the options introduced in the API. --- client/gatt.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/client/gatt.c b/client/gatt.c index 7dd3c94..fee1cf9 100644 --- a/client/gatt.c +++ b/client/gatt.c @@ -379,9 +379,23 @@ static void read_reply(DBusMessage *message, void *user_data) rl_hexdump(value, len); } +static void read_setup(DBusMessageIter *iter, void *user_data) +{ + DBusMessageIter dict; + + 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); + /* TODO: Add offset support */ + dbus_message_iter_close_container(iter, &dict); +} + static void read_attribute(GDBusProxy *proxy) { - if (g_dbus_proxy_method_call(proxy, "ReadValue", NULL, read_reply, + if (g_dbus_proxy_method_call(proxy, "ReadValue", read_setup, read_reply, NULL, NULL) == FALSE) { rl_printf("Failed to read\n"); return; @@ -421,12 +435,21 @@ static void write_reply(DBusMessage *message, void *user_data) static void write_setup(DBusMessageIter *iter, void *user_data) { struct iovec *iov = user_data; - DBusMessageIter array; + DBusMessageIter array, dict; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array); dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, &iov->iov_base, iov->iov_len); dbus_message_iter_close_container(iter, &array); + + 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); + /* TODO: Add offset support */ + dbus_message_iter_close_container(iter, &dict); } static void write_attribute(GDBusProxy *proxy, char *arg) -- 2.5.5 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCHv2 BlueZ 6/6] tools/gatt-service: Update to use new GATT API 2016-05-09 13:51 [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue Luiz Augusto von Dentz ` (3 preceding siblings ...) 2016-05-09 13:51 ` [PATCHv2 BlueZ 5/6] client: Update to use new GATT API Luiz Augusto von Dentz @ 2016-05-09 13:51 ` Luiz Augusto von Dentz 2016-05-09 22:57 ` [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue Vinicius Costa Gomes [not found] ` <CANCcNXdu8PZ7=iYeRO-4wir4hdmhuFCq_a7+VXdMgSXDNe_veA@mail.gmail.com> 6 siblings, 0 replies; 13+ messages in thread From: Luiz Augusto von Dentz @ 2016-05-09 13:51 UTC (permalink / raw) To: linux-bluetooth From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> This update use of ReadValue and WriteValue to include the options introduced in the API. --- tools/gatt-service.c | 159 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 126 insertions(+), 33 deletions(-) diff --git a/tools/gatt-service.c b/tools/gatt-service.c index 329d1af..0c78c4d 100644 --- a/tools/gatt-service.c +++ b/tools/gatt-service.c @@ -29,6 +29,7 @@ #include <stdio.h> #include <stdbool.h> #include <unistd.h> +#include <string.h> #include <sys/signalfd.h> #include <glib.h> @@ -127,32 +128,48 @@ static gboolean desc_get_value(const GDBusPropertyTable *property, return desc_read(desc, iter); } -static void desc_write(struct descriptor *desc, DBusMessageIter *iter) +static void desc_write(struct descriptor *desc, const uint8_t *value, int len) { - DBusMessageIter array; - const uint8_t *value; - int vlen; - - dbus_message_iter_recurse(iter, &array); - dbus_message_iter_get_fixed_array(&array, &value, &vlen); - g_free(desc->value); - desc->value = g_memdup(value, vlen); - desc->vlen = vlen; + desc->value = g_memdup(value, len); + desc->vlen = len; g_dbus_emit_property_changed(connection, desc->path, GATT_DESCRIPTOR_IFACE, "Value"); } +static int parse_value(DBusMessageIter *iter, const uint8_t **value, int *len) +{ + DBusMessageIter array; + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(iter, &array); + dbus_message_iter_get_fixed_array(&array, value, len); + + return 0; +} + static void desc_set_value(const GDBusPropertyTable *property, DBusMessageIter *iter, GDBusPendingPropertySet id, void *user_data) { struct descriptor *desc = user_data; + const uint8_t *value; + int len; printf("Descriptor(%s): Set(\"Value\", ...)\n", desc->uuid); - desc_write(desc, iter); + if (parse_value(iter, &value, &len)) { + printf("Invalid value for Set('Value'...)\n"); + g_dbus_pending_property_error(id, + ERROR_INTERFACE ".InvalidArguments", + "Invalid arguments in method call"); + return; + } + + desc_write(desc, value, len); g_dbus_pending_property_success(id); } @@ -249,15 +266,8 @@ static gboolean chr_get_props(const GDBusPropertyTable *property, return TRUE; } -static void chr_write(struct characteristic *chr, DBusMessageIter *iter) +static void chr_write(struct characteristic *chr, const uint8_t *value, int len) { - DBusMessageIter array; - uint8_t *value; - int len; - - dbus_message_iter_recurse(iter, &array); - dbus_message_iter_get_fixed_array(&array, &value, &len); - g_free(chr->value); chr->value = g_memdup(value, len); chr->vlen = len; @@ -271,10 +281,12 @@ static void chr_set_value(const GDBusPropertyTable *property, GDBusPendingPropertySet id, void *user_data) { struct characteristic *chr = user_data; + const uint8_t *value; + int len; printf("Characteristic(%s): Set('Value', ...)\n", chr->uuid); - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) { + if (!parse_value(iter, &value, &len)) { printf("Invalid value for Set('Value'...)\n"); g_dbus_pending_property_error(id, ERROR_INTERFACE ".InvalidArguments", @@ -282,7 +294,7 @@ static void chr_set_value(const GDBusPropertyTable *property, return; } - chr_write(chr, iter); + chr_write(chr, value, len); g_dbus_pending_property_success(id); } @@ -368,12 +380,53 @@ static void desc_iface_destroy(gpointer user_data) g_free(desc); } +static int parse_options(DBusMessageIter *iter, const char **device) +{ + DBusMessageIter dict; + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(iter, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + const char *key; + DBusMessageIter value, entry; + int var; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + + var = dbus_message_iter_get_arg_type(&value); + if (strcasecmp(key, "device") == 0) { + if (var != DBUS_TYPE_OBJECT_PATH) + return -EINVAL; + dbus_message_iter_get_basic(&value, device); + printf("Device: %s\n", *device); + } + } + + return 0; +} + static DBusMessage *chr_read_value(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct characteristic *chr = user_data; DBusMessage *reply; DBusMessageIter iter; + const char *device; + + if (!dbus_message_iter_init(msg, &iter)) + return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments"); + + if (parse_options(&iter, &device)) + return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments"); reply = dbus_message_new_method_return(msg); if (!reply) @@ -392,10 +445,21 @@ static DBusMessage *chr_write_value(DBusConnection *conn, DBusMessage *msg, { struct characteristic *chr = user_data; DBusMessageIter iter; + const uint8_t *value; + int len; + const char *device; dbus_message_iter_init(msg, &iter); - chr_write(chr, &iter); + if (parse_value(&iter, &value, &len)) + return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments"); + + if (parse_options(&iter, &device)) + return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments"); + + chr_write(chr, value, len); return dbus_message_new_method_return(msg); } @@ -415,10 +479,12 @@ static DBusMessage *chr_stop_notify(DBusConnection *conn, DBusMessage *msg, } static const GDBusMethodTable chr_methods[] = { - { GDBUS_ASYNC_METHOD("ReadValue", NULL, GDBUS_ARGS({ "value", "ay" }), - chr_read_value) }, - { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" }), - NULL, chr_write_value) }, + { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }), + GDBUS_ARGS({ "value", "ay" }), + chr_read_value) }, + { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" }, + { "options", "a{sv}" }), + NULL, chr_write_value) }, { GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL, chr_start_notify) }, { GDBUS_METHOD("StopNotify", NULL, NULL, chr_stop_notify) }, { } @@ -430,6 +496,15 @@ static DBusMessage *desc_read_value(DBusConnection *conn, DBusMessage *msg, struct descriptor *desc = user_data; DBusMessage *reply; DBusMessageIter iter; + const char *device; + + if (!dbus_message_iter_init(msg, &iter)) + return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments"); + + if (parse_options(&iter, &device)) + return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments"); reply = dbus_message_new_method_return(msg); if (!reply) @@ -438,6 +513,10 @@ static DBusMessage *desc_read_value(DBusConnection *conn, DBusMessage *msg, dbus_message_iter_init_append(reply, &iter); + if (parse_options(&iter, &device)) + return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments"); + desc_read(desc, &iter); return reply; @@ -448,20 +527,34 @@ static DBusMessage *desc_write_value(DBusConnection *conn, DBusMessage *msg, { struct descriptor *desc = user_data; DBusMessageIter iter; + const char *device; + const uint8_t *value; + int len; - dbus_message_iter_init(msg, &iter); + if (!dbus_message_iter_init(msg, &iter)) + return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments"); + + if (parse_value(&iter, &value, &len)) + return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments"); + + if (parse_options(&iter, &device)) + return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments"); - desc_write(desc, &iter); + desc_write(desc, value, len); return dbus_message_new_method_return(msg); } static const GDBusMethodTable desc_methods[] = { - { GDBUS_ASYNC_METHOD("ReadValue", NULL, GDBUS_ARGS({ "value", "ay" }), - desc_read_value) }, - { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" }), - NULL, - desc_write_value) }, + { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }), + GDBUS_ARGS({ "value", "ay" }), + desc_read_value) }, + { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" }, + { "options", "a{sv}" }), + NULL, desc_write_value) }, { } }; -- 2.5.5 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue 2016-05-09 13:51 [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue Luiz Augusto von Dentz ` (4 preceding siblings ...) 2016-05-09 13:51 ` [PATCHv2 BlueZ 6/6] tools/gatt-service: " Luiz Augusto von Dentz @ 2016-05-09 22:57 ` Vinicius Costa Gomes 2016-05-17 14:21 ` Luiz Augusto von Dentz [not found] ` <CANCcNXdu8PZ7=iYeRO-4wir4hdmhuFCq_a7+VXdMgSXDNe_veA@mail.gmail.com> 6 siblings, 1 reply; 13+ messages in thread From: Vinicius Costa Gomes @ 2016-05-09 22:57 UTC (permalink / raw) To: Luiz Augusto von Dentz, linux-bluetooth Hi Luiz, Luiz Augusto von Dentz <luiz.dentz@gmail.com> writes: > From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> > > This adds the possibility to pass an offset to these operations, and > also in the server case to give the device object. > --- > v2: Fix Vinicius comments, add necessary changes to other tools affected. > The series is looking good. Cheers, -- Vinicius ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue 2016-05-09 22:57 ` [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue Vinicius Costa Gomes @ 2016-05-17 14:21 ` Luiz Augusto von Dentz 2016-05-18 7:59 ` Kasper Markus (ETAS-PSC/ECE1) 0 siblings, 1 reply; 13+ messages in thread From: Luiz Augusto von Dentz @ 2016-05-17 14:21 UTC (permalink / raw) To: Vinicius Costa Gomes; +Cc: linux-bluetooth@vger.kernel.org Hi, On Tue, May 10, 2016 at 1:57 AM, Vinicius Costa Gomes <vinicius.gomes@intel.com> wrote: > Hi Luiz, > > Luiz Augusto von Dentz <luiz.dentz@gmail.com> writes: > >> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> >> >> This adds the possibility to pass an offset to these operations, and >> also in the server case to give the device object. >> --- >> v2: Fix Vinicius comments, add necessary changes to other tools affected. >> > > The series is looking good. If there are no comments to this set I will be pushing by the end of the day. -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue 2016-05-17 14:21 ` Luiz Augusto von Dentz @ 2016-05-18 7:59 ` Kasper Markus (ETAS-PSC/ECE1) 2016-05-18 13:55 ` Luiz Augusto von Dentz 0 siblings, 1 reply; 13+ messages in thread From: Kasper Markus (ETAS-PSC/ECE1) @ 2016-05-18 7:59 UTC (permalink / raw) To: linux-bluetooth@vger.kernel.org SGksIA0KDQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IGxpbnV4LWJsdWV0 b290aC1vd25lckB2Z2VyLmtlcm5lbC5vcmcgW21haWx0bzpsaW51eC1ibHVldG9vdGgtDQo+IG93 bmVyQHZnZXIua2VybmVsLm9yZ10gT24gQmVoYWxmIE9mIEx1aXogQXVndXN0byB2b24gRGVudHoN Cj4gU2VudDogVHVlc2RheSwgTWF5IDE3LCAyMDE2IDQ6MjIgUE0NCj4gU3ViamVjdDogUmU6IFtQ QVRDSHYyIEJsdWVaIDEvNl0gZG9jL2dhdHQtYXBpOiBBZGQgb3B0aW9ucyBkaWN0aW9uYXJ5IHRv DQo+IFJlYWRWYWx1ZS9Xcml0ZVZhbHVlDQo+IA0KPiBIaSwNCj4gDQo+IE9uIFR1ZSwgTWF5IDEw LCAyMDE2IGF0IDE6NTcgQU0sIFZpbmljaXVzIENvc3RhIEdvbWVzDQo+IDx2aW5pY2l1cy5nb21l c0BpbnRlbC5jb20+IHdyb3RlOg0KPiA+IEhpIEx1aXosDQo+ID4NCj4gPiBMdWl6IEF1Z3VzdG8g dm9uIERlbnR6IDxsdWl6LmRlbnR6QGdtYWlsLmNvbT4gd3JpdGVzOg0KPiA+DQo+ID4+IEZyb206 IEx1aXogQXVndXN0byB2b24gRGVudHogPGx1aXoudm9uLmRlbnR6QGludGVsLmNvbT4NCj4gPj4N Cj4gPj4gVGhpcyBhZGRzIHRoZSBwb3NzaWJpbGl0eSB0byBwYXNzIGFuIG9mZnNldCB0byB0aGVz ZSBvcGVyYXRpb25zLCBhbmQNCj4gPj4gYWxzbyBpbiB0aGUgc2VydmVyIGNhc2UgdG8gZ2l2ZSB0 aGUgZGV2aWNlIG9iamVjdC4NCj4gPj4gLS0tDQo+ID4+IHYyOiBGaXggVmluaWNpdXMgY29tbWVu dHMsIGFkZCBuZWNlc3NhcnkgY2hhbmdlcyB0byBvdGhlciB0b29scyBhZmZlY3RlZC4NCj4gPj4N Cj4gPg0KPiA+IFRoZSBzZXJpZXMgaXMgbG9va2luZyBnb29kLg0KPiANCj4gSWYgdGhlcmUgYXJl IG5vIGNvbW1lbnRzIHRvIHRoaXMgc2V0IEkgd2lsbCBiZSBwdXNoaW5nIGJ5IHRoZSBlbmQgb2Yg dGhlIGRheS4NCg0KQ3VycmVudGx5IHRoZSB3cml0ZSBjb21tYW5kIGluaGVyZW50bHkgc2VsZWN0 cyBhIHdyaXRlIG1ldGhvZCBiYXNlZCBvbiB0aGUgY2hhcmFjdGVyaXN0aWNzIHByb3BlcnRpZXMg KHdyaXRlLXdpdGhvdXQtcmVzcG9uc2UsIHJlbGlhYmxlLXdyaXRlLi4uKS4gDQpUaGUgb3B0aW9u IGRpY3Rpb25hcnkgd2l0aGluIHRoZSBBUEkgYWxsb3dzIGZvciBhZGRpbmcgYW5vdGhlciBvcHRp b24gdG8gb3ZlcnJpZGUgdGhlIGRlZmF1bHQgc2VsZWN0aW9uIG9mIHRoZSB3cml0ZSBtZXRob2Qg Zm9yIGNoYXJhY3RlcmlzdGljcyBzdXBwb3J0aW5nIG11bHRpcGxlIHdyaXRlIG9wdGlvbnMuIA0K SSB0aHVzIGNvbnNpZGVyIHRoaXMgcGF0Y2ggYSBtb3JlIGdlbmVyaWMgZW5hYmxlciB3aXRoaW4g dGhlIGdpdmVuIEFQSSB0byBwYXRoIHRoZSB3YXkgZm9yIGZ1cnRoZXIgaW1wcm92ZW1lbnRzLg0K DQpCZXN0IHJlZ2FyZHMsDQpNYXJrdXMNCg0K ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue 2016-05-18 7:59 ` Kasper Markus (ETAS-PSC/ECE1) @ 2016-05-18 13:55 ` Luiz Augusto von Dentz 2016-05-18 13:56 ` Luiz Augusto von Dentz 0 siblings, 1 reply; 13+ messages in thread From: Luiz Augusto von Dentz @ 2016-05-18 13:55 UTC (permalink / raw) To: Kasper Markus (ETAS-PSC/ECE1); +Cc: linux-bluetooth@vger.kernel.org Hi Markus, On Wed, May 18, 2016 at 10:59 AM, Kasper Markus (ETAS-PSC/ECE1) <Markus.Kasper@escrypt.com> wrote: > Hi, > >> -----Original Message----- >> From: linux-bluetooth-owner@vger.kernel.org [mailto:linux-bluetooth- >> owner@vger.kernel.org] On Behalf Of Luiz Augusto von Dentz >> Sent: Tuesday, May 17, 2016 4:22 PM >> Subject: Re: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to >> ReadValue/WriteValue >> >> Hi, >> >> On Tue, May 10, 2016 at 1:57 AM, Vinicius Costa Gomes >> <vinicius.gomes@intel.com> wrote: >> > Hi Luiz, >> > >> > Luiz Augusto von Dentz <luiz.dentz@gmail.com> writes: >> > >> >> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> >> >> >> >> This adds the possibility to pass an offset to these operations, and >> >> also in the server case to give the device object. >> >> --- >> >> v2: Fix Vinicius comments, add necessary changes to other tools affected. >> >> >> > >> > The series is looking good. >> >> If there are no comments to this set I will be pushing by the end of the day. > > Currently the write command inherently selects a write method based on the characteristics properties (write-without-response, reliable-write...). > The option dictionary within the API allows for adding another option to override the default selection of the write method for characteristics supporting multiple write options. > I thus consider this patch a more generic enabler within the given API to path the way for further improvements. Yes, I don't know where using a specific method would actually be recommended since it the server should be able to indicate the proper operation to use via properties but in case there is a real case where the server has the properties somewhat broken then perhaps we can include such feature. -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue 2016-05-18 13:55 ` Luiz Augusto von Dentz @ 2016-05-18 13:56 ` Luiz Augusto von Dentz 2016-05-18 15:31 ` Kasper Markus (ETAS-PSC/ECE1) 0 siblings, 1 reply; 13+ messages in thread From: Luiz Augusto von Dentz @ 2016-05-18 13:56 UTC (permalink / raw) To: Kasper Markus (ETAS-PSC/ECE1); +Cc: linux-bluetooth@vger.kernel.org Hi, On Wed, May 18, 2016 at 4:55 PM, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote: > Hi Markus, > > On Wed, May 18, 2016 at 10:59 AM, Kasper Markus (ETAS-PSC/ECE1) > <Markus.Kasper@escrypt.com> wrote: >> Hi, >> >>> -----Original Message----- >>> From: linux-bluetooth-owner@vger.kernel.org [mailto:linux-bluetooth- >>> owner@vger.kernel.org] On Behalf Of Luiz Augusto von Dentz >>> Sent: Tuesday, May 17, 2016 4:22 PM >>> Subject: Re: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to >>> ReadValue/WriteValue >>> >>> Hi, >>> >>> On Tue, May 10, 2016 at 1:57 AM, Vinicius Costa Gomes >>> <vinicius.gomes@intel.com> wrote: >>> > Hi Luiz, >>> > >>> > Luiz Augusto von Dentz <luiz.dentz@gmail.com> writes: >>> > >>> >> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> >>> >> >>> >> This adds the possibility to pass an offset to these operations, and >>> >> also in the server case to give the device object. >>> >> --- >>> >> v2: Fix Vinicius comments, add necessary changes to other tools affected. >>> >> >>> > >>> > The series is looking good. >>> >>> If there are no comments to this set I will be pushing by the end of the day. >> >> Currently the write command inherently selects a write method based on the characteristics properties (write-without-response, reliable-write...). >> The option dictionary within the API allows for adding another option to override the default selection of the write method for characteristics supporting multiple write options. >> I thus consider this patch a more generic enabler within the given API to path the way for further improvements. > > Yes, I don't know where using a specific method would actually be > recommended since it the server should be able to indicate the proper > operation to use via properties but in case there is a real case where > the server has the properties somewhat broken then perhaps we can > include such feature. > > -- > Luiz Augusto von Dentz Btw, these patches are now upstream. -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue 2016-05-18 13:56 ` Luiz Augusto von Dentz @ 2016-05-18 15:31 ` Kasper Markus (ETAS-PSC/ECE1) 0 siblings, 0 replies; 13+ messages in thread From: Kasper Markus (ETAS-PSC/ECE1) @ 2016-05-18 15:31 UTC (permalink / raw) To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org Hi Luiz, > -----Original Message----- > From: Luiz Augusto von Dentz [mailto:luiz.dentz@gmail.com] > Sent: Wednesday, May 18, 2016 3:56 PM > To: Kasper Markus (ETAS-PSC/ECE1) <Markus.Kasper@escrypt.com> > Cc: linux-bluetooth@vger.kernel.org > Subject: Re: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to > ReadValue/WriteValue > > Hi, > > On Wed, May 18, 2016 at 4:55 PM, Luiz Augusto von Dentz > <luiz.dentz@gmail.com> wrote: > > Hi Markus, > > > > On Wed, May 18, 2016 at 10:59 AM, Kasper Markus (ETAS-PSC/ECE1) > > <Markus.Kasper@escrypt.com> wrote: > >> Hi, > >> > >>> -----Original Message----- > >>> From: linux-bluetooth-owner@vger.kernel.org [mailto:linux-bluetooth- > >>> owner@vger.kernel.org] On Behalf Of Luiz Augusto von Dentz > >>> Sent: Tuesday, May 17, 2016 4:22 PM > >>> Subject: Re: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options > >>> dictionary to ReadValue/WriteValue > >>> > >>> Hi, > >>> > >>> On Tue, May 10, 2016 at 1:57 AM, Vinicius Costa Gomes > >>> <vinicius.gomes@intel.com> wrote: > >>> > Hi Luiz, > >>> > > >>> > Luiz Augusto von Dentz <luiz.dentz@gmail.com> writes: > >>> > > >>> >> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> > >>> >> > >>> >> This adds the possibility to pass an offset to these operations, > >>> >> and also in the server case to give the device object. > >>> >> --- > >>> >> v2: Fix Vinicius comments, add necessary changes to other tools > affected. > >>> >> > >>> > > >>> > The series is looking good. > >>> > >>> If there are no comments to this set I will be pushing by the end of the day. > >> > >> Currently the write command inherently selects a write method based on the > characteristics properties (write-without-response, reliable-write...). > >> The option dictionary within the API allows for adding another option to > override the default selection of the write method for characteristics supporting > multiple write options. > >> I thus consider this patch a more generic enabler within the given API to path > the way for further improvements. > > > > Yes, I don't know where using a specific method would actually be > > recommended since it the server should be able to indicate the proper > > operation to use via properties but in case there is a real case where > > the server has the properties somewhat broken then perhaps we can > > include such feature. > > > > -- > > Luiz Augusto von Dentz > > Btw, these patches are now upstream. > I'm facing this problem for an iOS peripheral, where the properties of a characteristic are set to "write-without-response" only. The iOS stack adds a "reliable-write" descriptor to these characteristics, although write is not supported. While I'm quite sure the Apple stack does not behave correctly when advertising the "reliable-write" extended property for a characteristic without "write" property, having control over bluez's writes would be the easiest way to handle this. My current fix is a patched bluez: I modified the condition for a reliable write to check for both flags: "write" & "reliable-write" before using the reliable-write code. Markus > -- > Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 13+ messages in thread
[parent not found: <CANCcNXdu8PZ7=iYeRO-4wir4hdmhuFCq_a7+VXdMgSXDNe_veA@mail.gmail.com>]
* Re: [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue [not found] ` <CANCcNXdu8PZ7=iYeRO-4wir4hdmhuFCq_a7+VXdMgSXDNe_veA@mail.gmail.com> @ 2016-05-17 21:16 ` Puthikorn Voravootivat 0 siblings, 0 replies; 13+ messages in thread From: Puthikorn Voravootivat @ 2016-05-17 21:16 UTC (permalink / raw) To: Luiz Augusto von Dentz; +Cc: linux-bluetooth, Vinicius Costa Gomes *resend in plain text Hi. I found a possible bug below. Comment in line. Thanks On Mon, May 9, 2016 at 6:51 AM, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote: > > From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> > > This adds the possibility to pass an offset to these operations, and > also in the server case to give the device object. > --- > v2: Fix Vinicius comments, add necessary changes to other tools affected. > > doc/gatt-api.txt | 20 ++++- > src/gatt-client.c | 180 ++++++++++++++++++++++++++++-------------- > src/gatt-database.c | 219 ++++++++++++++++++++++++++++++++++++++-------------- > 3 files changed, 296 insertions(+), 123 deletions(-) > > diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt > index ad2ab16..683b1b7 100644 > --- a/doc/gatt-api.txt > +++ b/doc/gatt-api.txt > @@ -61,23 +61,29 @@ Service org.bluez > Interface org.bluez.GattCharacteristic1 [Experimental] > Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY > > -Methods array{byte} ReadValue() > +Methods array{byte} ReadValue(dict options) > > Issues a request to read the value of the > characteristic and returns the value if the > operation was successful. > > + Possible options: "offset": uint16 offset > + "device": Object Device (Server only) > + > Possible Errors: org.bluez.Error.Failed > org.bluez.Error.InProgress > org.bluez.Error.NotPermitted > org.bluez.Error.NotAuthorized > org.bluez.Error.NotSupported > > - void WriteValue(array{byte} value) > + void WriteValue(array{byte} value, dict options) > > Issues a request to write the value of the > characteristic. > > + Possible options: "offset": Start offset > + "device": Device path (Server only) > + > Possible Errors: org.bluez.Error.Failed > org.bluez.Error.InProgress > org.bluez.Error.NotPermitted > @@ -154,23 +160,29 @@ Service org.bluez > Interface org.bluez.GattDescriptor1 [Experimental] > Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY/descriptorZZZ > > -Methods array{byte} ReadValue() > +Methods array{byte} ReadValue(dict flags) > > Issues a request to read the value of the > characteristic and returns the value if the > operation was successful. > > + Possible options: "offset": Start offset > + "device": Device path (Server only) > + > Possible Errors: org.bluez.Error.Failed > org.bluez.Error.InProgress > org.bluez.Error.NotPermitted > org.bluez.Error.NotAuthorized > org.bluez.Error.NotSupported > > - void WriteValue(array{byte} value) > + void WriteValue(array{byte} value, dict flags) > > Issues a request to write the value of the > characteristic. > > + Possible options: "offset": Start offset > + "device": Device path (Server only) > + > Possible Errors: org.bluez.Error.Failed > org.bluez.Error.InProgress > org.bluez.Error.NotPermitted > diff --git a/src/gatt-client.c b/src/gatt-client.c > index 16a1f6c..0cbacca 100644 > --- a/src/gatt-client.c > +++ b/src/gatt-client.c > @@ -23,6 +23,7 @@ > > #include <stdbool.h> > #include <stdint.h> > +#include <errno.h> > > #include <dbus/dbus.h> > > @@ -191,33 +192,17 @@ static gboolean descriptor_value_exists(const GDBusPropertyTable *property, > return ret; > } > > -static bool parse_value_arg(DBusMessage *msg, uint8_t **value, > - size_t *value_len) > +static int parse_value_arg(DBusMessageIter *iter, uint8_t **value, int *len) > { > - DBusMessageIter iter, array; > - uint8_t *val; > - int len; > - > - if (!dbus_message_iter_init(msg, &iter)) > - return false; > - > - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) > - return false; > - > - dbus_message_iter_recurse(&iter, &array); > - dbus_message_iter_get_fixed_array(&array, &val, &len); > - dbus_message_iter_next(&iter); > - > - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) > - return false; > + DBusMessageIter array; > > - if (len < 0) > - return false; > + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) > + return -EINVAL; > > - *value = val; > - *value_len = len; > + dbus_message_iter_recurse(iter, &array); > + dbus_message_iter_get_fixed_array(&array, value, len); > > - return true; > + return 0; > } > > typedef bool (*async_dbus_op_complete_t)(void *data); > @@ -390,12 +375,60 @@ fail: > return; > } > > +static int parse_options(DBusMessageIter *iter, uint16_t *offset) > +{ > + DBusMessageIter dict; > + > + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) > + return -EINVAL; > + > + dbus_message_iter_recurse(iter, &dict); > + > + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { > + const char *key; > + DBusMessageIter value, entry; > + int var; > + > + dbus_message_iter_recurse(&dict, &entry); > + dbus_message_iter_get_basic(&entry, &key); > + > + dbus_message_iter_next(&entry); > + dbus_message_iter_recurse(&entry, &value); > + > + var = dbus_message_iter_get_arg_type(&value); > + if (strcasecmp(key, "offset") == 0) { > + if (var != DBUS_TYPE_UINT16) > + return -EINVAL; > + dbus_message_iter_get_basic(&value, offset); > + } Add dbus_message_iter_next(&dict); here? > > + } > + > + return 0; > +} > + > +static unsigned int read_value(struct bt_gatt_client *gatt, uint16_t handle, > + bt_gatt_client_read_callback_t callback, > + struct async_dbus_op *op) > +{ > + if (op->offset) > + return bt_gatt_client_read_long_value(gatt, handle, op->offset, > + callback, > + async_dbus_op_ref(op), > + async_dbus_op_unref); > + else > + return bt_gatt_client_read_value(gatt, handle, callback, > + async_dbus_op_ref(op), > + async_dbus_op_unref); > +} > + > static DBusMessage *descriptor_read_value(DBusConnection *conn, > DBusMessage *msg, void *user_data) > { > struct descriptor *desc = user_data; > struct bt_gatt_client *gatt = desc->chrc->service->client->gatt; > + DBusMessageIter iter; > struct async_dbus_op *op; > + uint16_t offset = 0; > > if (!gatt) > return btd_error_failed(msg, "Not connected"); > @@ -403,14 +436,17 @@ static DBusMessage *descriptor_read_value(DBusConnection *conn, > if (desc->read_id) > return btd_error_in_progress(msg); > > + dbus_message_iter_init(msg, &iter); > + > + if (parse_options(&iter, &offset)) > + return btd_error_invalid_args(msg); > + > op = new0(struct async_dbus_op, 1); > op->msg = dbus_message_ref(msg); > op->data = desc; > + op->offset = offset; > > - desc->read_id = bt_gatt_client_read_value(gatt, desc->handle, > - desc_read_cb, > - async_dbus_op_ref(op), > - async_dbus_op_unref); > + desc->read_id = read_value(gatt, desc->handle, desc_read_cb, op); > if (desc->read_id) > return NULL; > > @@ -450,7 +486,6 @@ done: > g_dbus_send_message(btd_get_dbus_connection(), reply); > } > > - > static void write_cb(bool success, uint8_t att_ecode, void *user_data) > { > write_result_cb(success, false, att_ecode, user_data); > @@ -459,7 +494,8 @@ static void write_cb(bool success, uint8_t att_ecode, void *user_data) > static unsigned int start_long_write(DBusMessage *msg, uint16_t handle, > struct bt_gatt_client *gatt, > bool reliable, const uint8_t *value, > - size_t value_len, void *data, > + size_t value_len, uint16_t offset, > + void *data, > async_dbus_op_complete_t complete) > { > struct async_dbus_op *op; > @@ -469,9 +505,10 @@ static unsigned int start_long_write(DBusMessage *msg, uint16_t handle, > op->msg = dbus_message_ref(msg); > op->data = data; > op->complete = complete; > + op->offset = offset; > > - id = bt_gatt_client_write_long_value(gatt, reliable, handle, > - 0, value, value_len, > + id = bt_gatt_client_write_long_value(gatt, reliable, handle, offset, > + value, value_len, > write_result_cb, op, > async_dbus_op_free); > > @@ -522,8 +559,10 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn, > { > struct descriptor *desc = user_data; > struct bt_gatt_client *gatt = desc->chrc->service->client->gatt; > + DBusMessageIter iter; > uint8_t *value = NULL; > - size_t value_len = 0; > + int value_len = 0; > + uint16_t offset = 0; > > if (!gatt) > return btd_error_failed(msg, "Not connected"); > @@ -531,7 +570,12 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn, > if (desc->write_id) > return btd_error_in_progress(msg); > > - if (!parse_value_arg(msg, &value, &value_len)) > + dbus_message_iter_init(msg, &iter); > + > + if (parse_value_arg(&iter, &value, &value_len)) > + return btd_error_invalid_args(msg); > + > + if (parse_options(&iter, &offset)) > return btd_error_invalid_args(msg); > > /* > @@ -546,15 +590,15 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn, > * Based on the value length and the MTU, either use a write or a long > * write. > */ > - if (value_len <= (unsigned) bt_gatt_client_get_mtu(gatt) - 3) > + if (value_len <= bt_gatt_client_get_mtu(gatt) - 3 && !offset) > desc->write_id = start_write_request(msg, desc->handle, > gatt, value, > value_len, desc, > desc_write_complete); > else > - desc->write_id = start_long_write(msg, desc->handle, > - gatt, false, value, > - value_len, desc, > + desc->write_id = start_long_write(msg, desc->handle, gatt, > + false, value, > + value_len, offset, desc, > desc_write_complete); > > if (!desc->write_id) > @@ -574,13 +618,15 @@ static const GDBusPropertyTable descriptor_properties[] = { > }; > > static const GDBusMethodTable descriptor_methods[] = { > - { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue", NULL, > - GDBUS_ARGS({ "value", "ay" }), > - descriptor_read_value) }, > + { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue", > + GDBUS_ARGS({ "options", "a{sv}" }), > + GDBUS_ARGS({ "value", "ay" }), > + descriptor_read_value) }, > { GDBUS_EXPERIMENTAL_ASYNC_METHOD("WriteValue", > - GDBUS_ARGS({ "value", "ay" }), > - NULL, > - descriptor_write_value) }, > + GDBUS_ARGS({ "value", "ay" }, > + { "options", "a{sv}" }), > + NULL, > + descriptor_write_value) }, > { } > }; > > @@ -837,7 +883,9 @@ static DBusMessage *characteristic_read_value(DBusConnection *conn, > { > struct characteristic *chrc = user_data; > struct bt_gatt_client *gatt = chrc->service->client->gatt; > + DBusMessageIter iter; > struct async_dbus_op *op; > + uint16_t offset = 0; > > if (!gatt) > return btd_error_failed(msg, "Not connected"); > @@ -845,14 +893,17 @@ static DBusMessage *characteristic_read_value(DBusConnection *conn, > if (chrc->read_id) > return btd_error_in_progress(msg); > > + dbus_message_iter_init(msg, &iter); > + > + if (parse_options(&iter, &offset)) > + return btd_error_invalid_args(msg); > + > op = new0(struct async_dbus_op, 1); > op->msg = dbus_message_ref(msg); > op->data = chrc; > + op->offset = offset; > > - chrc->read_id = bt_gatt_client_read_value(gatt, chrc->value_handle, > - chrc_read_cb, > - async_dbus_op_ref(op), > - async_dbus_op_unref); > + chrc->read_id = read_value(gatt, chrc->value_handle, chrc_read_cb, op); > if (chrc->read_id) > return NULL; > > @@ -879,9 +930,11 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn, > { > struct characteristic *chrc = user_data; > struct bt_gatt_client *gatt = chrc->service->client->gatt; > + DBusMessageIter iter; > uint8_t *value = NULL; > - size_t value_len = 0; > + int value_len = 0; > bool supported = false; > + uint16_t offset = 0; > > if (!gatt) > return btd_error_failed(msg, "Not connected"); > @@ -889,7 +942,12 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn, > if (chrc->write_id) > return btd_error_in_progress(msg); > > - if (!parse_value_arg(msg, &value, &value_len)) > + dbus_message_iter_init(msg, &iter); > + > + if (parse_value_arg(&iter, &value, &value_len)) > + return btd_error_invalid_args(msg); > + > + if (parse_options(&iter, &offset)) > return btd_error_invalid_args(msg); > > /* > @@ -906,7 +964,7 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn, > if ((chrc->ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE)) { > supported = true; > chrc->write_id = start_long_write(msg, chrc->value_handle, gatt, > - true, value, value_len, > + true, value, value_len, offset, > chrc, chrc_write_complete); > if (chrc->write_id) > return NULL; > @@ -920,7 +978,7 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn, > if (!mtu) > return btd_error_failed(msg, "No ATT transport"); > > - if (value_len <= (unsigned) mtu - 3) > + if (value_len <= mtu - 3 && !offset) > chrc->write_id = start_write_request(msg, > chrc->value_handle, > gatt, value, value_len, > @@ -928,7 +986,7 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn, > else > chrc->write_id = start_long_write(msg, > chrc->value_handle, gatt, > - false, value, value_len, > + false, value, value_len, offset, > chrc, chrc_write_complete); > > if (chrc->write_id) > @@ -1242,17 +1300,19 @@ static const GDBusPropertyTable characteristic_properties[] = { > }; > > static const GDBusMethodTable characteristic_methods[] = { > - { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue", NULL, > - GDBUS_ARGS({ "value", "ay" }), > - characteristic_read_value) }, > + { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue", > + GDBUS_ARGS({ "options", "a{sv}" }), > + GDBUS_ARGS({ "value", "ay" }), > + characteristic_read_value) }, > { GDBUS_EXPERIMENTAL_ASYNC_METHOD("WriteValue", > - GDBUS_ARGS({ "value", "ay" }), > - NULL, > - characteristic_write_value) }, > + GDBUS_ARGS({ "value", "ay" }, > + { "options", "a{sv}" }), > + NULL, > + characteristic_write_value) }, > { GDBUS_EXPERIMENTAL_ASYNC_METHOD("StartNotify", NULL, NULL, > - characteristic_start_notify) }, > + characteristic_start_notify) }, > { GDBUS_EXPERIMENTAL_METHOD("StopNotify", NULL, NULL, > - characteristic_stop_notify) }, > + characteristic_stop_notify) }, > { } > }; > > diff --git a/src/gatt-database.c b/src/gatt-database.c > index b8da955..99d084d 100644 > --- a/src/gatt-database.c > +++ b/src/gatt-database.c > @@ -135,6 +135,7 @@ struct external_desc { > }; > > struct pending_op { > + struct btd_device *device; > unsigned int id; > struct gatt_db_attribute *attrib; > struct queue *owner_queue; > @@ -1592,7 +1593,8 @@ static void pending_op_free(void *data) > free(op); > } > > -static struct pending_op *pending_read_new(struct queue *owner_queue, > +static struct pending_op *pending_read_new(struct btd_device *device, > + struct queue *owner_queue, > struct gatt_db_attribute *attrib, > unsigned int id) > { > @@ -1601,6 +1603,7 @@ static struct pending_op *pending_read_new(struct queue *owner_queue, > op = new0(struct pending_op, 1); > > op->owner_queue = owner_queue; > + op->device = device; > op->attrib = attrib; > op->id = id; > queue_push_tail(owner_queue, op); > @@ -1608,33 +1611,75 @@ static struct pending_op *pending_read_new(struct queue *owner_queue, > return op; > } > > -static void send_read(struct gatt_db_attribute *attrib, GDBusProxy *proxy, > - struct queue *owner_queue, > - unsigned int id) > +static void append_options(DBusMessageIter *iter, void *user_data) > +{ > + struct pending_op *op = user_data; > + const char *path = device_get_path(op->device); > + > + dict_append_entry(iter, "device", DBUS_TYPE_OBJECT_PATH, &path); > +} > + > +static void read_setup_cb(DBusMessageIter *iter, void *user_data) > +{ > + struct pending_op *op = user_data; > + DBusMessageIter dict; > + > + 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); > + > + append_options(&dict, op); > + > + dbus_message_iter_close_container(iter, &dict); > +} > + > +static struct pending_op *send_read(struct btd_device *device, > + struct gatt_db_attribute *attrib, > + GDBusProxy *proxy, > + struct queue *owner_queue, > + unsigned int id) > { > struct pending_op *op; > - uint8_t ecode = BT_ATT_ERROR_UNLIKELY; > > - op = pending_read_new(owner_queue, attrib, id); > + op = pending_read_new(device, owner_queue, attrib, id); > > - if (g_dbus_proxy_method_call(proxy, "ReadValue", NULL, read_reply_cb, > - op, pending_op_free) == TRUE) > - return; > + if (g_dbus_proxy_method_call(proxy, "ReadValue", read_setup_cb, > + read_reply_cb, op, pending_op_free) == TRUE) > + return op; > > pending_op_free(op); > > - gatt_db_attribute_read_result(attrib, id, ecode, NULL, 0); > + return NULL; > } > > static void write_setup_cb(DBusMessageIter *iter, void *user_data) > { > struct pending_op *op = user_data; > - DBusMessageIter array; > + DBusMessageIter array, dict; > > dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array); > dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, > &op->data.iov_base, op->data.iov_len); > dbus_message_iter_close_container(iter, &array); > + > + 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); > + > + append_options(&dict, op); > + > + dbus_message_iter_close_container(iter, &dict); > + > + if (!op->owner_queue) { > + gatt_db_attribute_write_result(op->attrib, op->id, 0); > + pending_op_free(op); > + } > } > > static void write_reply_cb(DBusMessage *message, void *user_data) > @@ -1673,7 +1718,8 @@ done: > gatt_db_attribute_write_result(op->attrib, op->id, ecode); > } > > -static struct pending_op *pending_write_new(struct queue *owner_queue, > +static struct pending_op *pending_write_new(struct btd_device *device, > + struct queue *owner_queue, > struct gatt_db_attribute *attrib, > unsigned int id, > const uint8_t *value, > @@ -1686,6 +1732,7 @@ static struct pending_op *pending_write_new(struct queue *owner_queue, > op->data.iov_base = (uint8_t *) value; > op->data.iov_len = len; > > + op->device = device; > op->owner_queue = owner_queue; > op->attrib = attrib; > op->id = id; > @@ -1694,24 +1741,25 @@ static struct pending_op *pending_write_new(struct queue *owner_queue, > return op; > } > > -static void send_write(struct gatt_db_attribute *attrib, GDBusProxy *proxy, > +static struct pending_op *send_write(struct btd_device *device, > + struct gatt_db_attribute *attrib, > + GDBusProxy *proxy, > struct queue *owner_queue, > unsigned int id, > const uint8_t *value, size_t len) > { > struct pending_op *op; > - uint8_t ecode = BT_ATT_ERROR_UNLIKELY; > > - op = pending_write_new(owner_queue, attrib, id, value, len); > + op = pending_write_new(device, owner_queue, attrib, id, value, len); > > if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup_cb, > - write_reply_cb, op, > - pending_op_free) == TRUE) > - return; > + owner_queue ? write_reply_cb : NULL, > + op, pending_op_free) == TRUE) > + return op; > > pending_op_free(op); > > - gatt_db_attribute_write_result(attrib, id, ecode); > + return NULL; > } > > static uint32_t permissions_from_props(uint8_t props, uint8_t ext_props) > @@ -1895,19 +1943,65 @@ static bool database_add_cep(struct external_service *service, > return true; > } > > +static struct btd_device *att_get_device(struct bt_att *att) > +{ > + GIOChannel *io = NULL; > + GError *gerr = NULL; > + bdaddr_t src, dst; > + uint8_t dst_type; > + struct btd_adapter *adapter; > + > + io = g_io_channel_unix_new(bt_att_get_fd(att)); > + if (!io) > + return NULL; > + > + bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, > + BT_IO_OPT_DEST_BDADDR, &dst, > + BT_IO_OPT_DEST_TYPE, &dst_type, > + BT_IO_OPT_INVALID); > + if (gerr) { > + error("bt_io_get: %s", gerr->message); > + g_error_free(gerr); > + g_io_channel_unref(io); > + return NULL; > + } > + > + g_io_channel_unref(io); > + > + adapter = adapter_find(&src); > + if (!adapter) { > + error("Unable to find adapter object"); > + return NULL; > + } > + > + return btd_adapter_find_device(adapter, &dst, dst_type); > +} > + > static void desc_read_cb(struct gatt_db_attribute *attrib, > unsigned int id, uint16_t offset, > uint8_t opcode, struct bt_att *att, > void *user_data) > { > struct external_desc *desc = user_data; > + struct btd_device *device; > > if (desc->attrib != attrib) { > error("Read callback called with incorrect attribute"); > - return; > + goto fail; > } > > - send_read(attrib, desc->proxy, desc->pending_reads, id); > + device = att_get_device(att); > + if (!device) { > + error("Unable to find device object"); > + goto fail; > + } > + > + if (send_read(device, attrib, desc->proxy, desc->pending_reads, id)) > + return; > + > +fail: > + gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY, > + NULL, 0); > } > > static void desc_write_cb(struct gatt_db_attribute *attrib, > @@ -1917,13 +2011,26 @@ static void desc_write_cb(struct gatt_db_attribute *attrib, > void *user_data) > { > struct external_desc *desc = user_data; > + struct btd_device *device; > > if (desc->attrib != attrib) { > error("Read callback called with incorrect attribute"); > - return; > + goto fail; > } > > - send_write(attrib, desc->proxy, desc->pending_writes, id, value, len); > + device = att_get_device(att); > + if (!device) { > + error("Unable to find device object"); > + goto fail; > + } > + > + if (send_write(device, attrib, desc->proxy, desc->pending_writes, id, > + value, len)) > + return; > + > +fail: > + gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY, > + NULL, 0); > } > > static bool database_add_desc(struct external_service *service, > @@ -1956,43 +2063,25 @@ static void chrc_read_cb(struct gatt_db_attribute *attrib, > void *user_data) > { > struct external_chrc *chrc = user_data; > + struct btd_device *device; > > if (chrc->attrib != attrib) { > error("Read callback called with incorrect attribute"); > - return; > + goto fail; > } > > - send_read(attrib, chrc->proxy, chrc->pending_reads, id); > -} > - > -static void write_without_response_setup_cb(DBusMessageIter *iter, > - void *user_data) > -{ > - struct iovec *iov = user_data; > - DBusMessageIter array; > - > - dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array); > - dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, > - &iov->iov_base, iov->iov_len); > - dbus_message_iter_close_container(iter, &array); > -} > - > -static void send_write_without_response(struct gatt_db_attribute *attrib, > - GDBusProxy *proxy, unsigned int id, > - const uint8_t *value, size_t len) > -{ > - struct iovec iov; > - uint8_t ecode = 0; > - > - iov.iov_base = (uint8_t *) value; > - iov.iov_len = len; > + device = att_get_device(att); > + if (!device) { > + error("Unable to find device object"); > + goto fail; > + } > > - if (!g_dbus_proxy_method_call(proxy, "WriteValue", > - write_without_response_setup_cb, > - NULL, &iov, NULL)) > - ecode = BT_ATT_ERROR_UNLIKELY; > + if (send_read(device, attrib, chrc->proxy, chrc->pending_reads, id)) > + return; > > - gatt_db_attribute_write_result(attrib, id, ecode); > +fail: > + gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY, > + NULL, 0); > } > > static void chrc_write_cb(struct gatt_db_attribute *attrib, > @@ -2002,19 +2091,31 @@ static void chrc_write_cb(struct gatt_db_attribute *attrib, > void *user_data) > { > struct external_chrc *chrc = user_data; > + struct btd_device *device; > + struct queue *queue; > > if (chrc->attrib != attrib) { > error("Write callback called with incorrect attribute"); > - return; > + goto fail; > } > > - if (chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) { > - send_write_without_response(attrib, chrc->proxy, id, value, > - len); > - return; > + device = att_get_device(att); > + if (!device) { > + error("Unable to find device object"); > + goto fail; > } > > - send_write(attrib, chrc->proxy, chrc->pending_writes, id, value, len); > + if (!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP)) > + queue = chrc->pending_writes; > + else > + queue = NULL; > + > + if (send_write(device, attrib, chrc->proxy, queue, id, value, len)) > + return; > + > +fail: > + gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY, > + NULL, 0); > } > > static bool database_add_chrc(struct external_service *service, > -- > 2.5.5 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2016-05-18 15:31 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-05-09 13:51 [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue Luiz Augusto von Dentz
2016-05-09 13:51 ` [PATCHv2 BlueZ 2/6] doc/gatt-api: Merge RegisterProfile with RegisterApplication Luiz Augusto von Dentz
2016-05-09 13:51 ` [PATCHv2 BlueZ 3/6] doc/gatt-api: Add secure flags Luiz Augusto von Dentz
2016-05-09 13:51 ` [PATCHv2 BlueZ 4/6] test: Update GATT examples with the new API Luiz Augusto von Dentz
2016-05-09 13:51 ` [PATCHv2 BlueZ 5/6] client: Update to use new GATT API Luiz Augusto von Dentz
2016-05-09 13:51 ` [PATCHv2 BlueZ 6/6] tools/gatt-service: " Luiz Augusto von Dentz
2016-05-09 22:57 ` [PATCHv2 BlueZ 1/6] doc/gatt-api: Add options dictionary to ReadValue/WriteValue Vinicius Costa Gomes
2016-05-17 14:21 ` Luiz Augusto von Dentz
2016-05-18 7:59 ` Kasper Markus (ETAS-PSC/ECE1)
2016-05-18 13:55 ` Luiz Augusto von Dentz
2016-05-18 13:56 ` Luiz Augusto von Dentz
2016-05-18 15:31 ` Kasper Markus (ETAS-PSC/ECE1)
[not found] ` <CANCcNXdu8PZ7=iYeRO-4wir4hdmhuFCq_a7+VXdMgSXDNe_veA@mail.gmail.com>
2016-05-17 21:16 ` Puthikorn Voravootivat
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.