1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * BlueZ - Bluetooth protocol stack for Linux
6 * Copyright (C) 2014 Google Inc.
21 #include <dbus/dbus.h>
23 #include "lib/bluetooth.h"
27 #include "gdbus/gdbus.h"
28 #include "btio/btio.h"
35 #include "src/shared/io.h"
36 #include "src/shared/queue.h"
37 #include "src/shared/att.h"
38 #include "src/shared/gatt-db.h"
39 #include "src/shared/gatt-client.h"
40 #include "src/shared/util.h"
41 #include "gatt-client.h"
42 #include "dbus-common.h"
45 #define NELEM(x) (sizeof(x) / sizeof((x)[0]))
48 #define GATT_SERVICE_IFACE "org.bluez.GattService1"
49 #define GATT_CHARACTERISTIC_IFACE "org.bluez.GattCharacteristic1"
50 #define GATT_DESCRIPTOR_IFACE "org.bluez.GattDescriptor1"
52 struct btd_gatt_client {
53 struct btd_device *device;
58 struct bt_gatt_client *gatt;
60 struct queue *services;
61 struct queue *all_notify_clients;
63 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
69 struct btd_gatt_client *client;
71 uint16_t start_handle;
76 struct queue *incl_services;
77 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
79 struct queue *pending_ext_props;
84 typedef bool (*async_dbus_op_complete_t)(void *data);
86 struct async_dbus_op {
92 async_dbus_op_complete_t complete;
98 void (*destroy)(void *data);
102 struct characteristic {
103 struct service *service;
104 struct gatt_db_attribute *attr;
106 uint16_t value_handle;
109 uint16_t ext_props_handle;
113 unsigned int ready_id;
114 unsigned int exchange_id;
115 struct sock_io *write_io;
116 struct sock_io *notify_io;
118 struct async_dbus_op *read_op;
119 struct async_dbus_op *write_op;
124 struct queue *notify_clients;
128 struct characteristic *chrc;
129 struct gatt_db_attribute *attr;
134 struct async_dbus_op *read_op;
135 struct async_dbus_op *write_op;
138 static bool uuid_cmp(const bt_uuid_t *uuid, uint16_t u16)
142 bt_uuid16_create(&uuid16, u16);
144 return bt_uuid_cmp(uuid, &uuid16) == 0;
147 static gboolean descriptor_get_uuid(const GDBusPropertyTable *property,
148 DBusMessageIter *iter, void *data)
150 char uuid[MAX_LEN_UUID_STR + 1];
151 const char *ptr = uuid;
152 struct descriptor *desc = data;
154 bt_uuid_to_string(&desc->uuid, uuid, sizeof(uuid));
155 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
160 static gboolean descriptor_get_characteristic(
161 const GDBusPropertyTable *property,
162 DBusMessageIter *iter, void *data)
164 struct descriptor *desc = data;
165 const char *str = desc->chrc->path;
167 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &str);
172 static void read_cb(struct gatt_db_attribute *attrib, int err,
173 const uint8_t *value, size_t length,
176 DBusMessageIter *array = user_data;
181 dbus_message_iter_append_fixed_array(array, DBUS_TYPE_BYTE, &value,
185 static gboolean descriptor_get_value(const GDBusPropertyTable *property,
186 DBusMessageIter *iter, void *data)
188 struct descriptor *desc = data;
189 DBusMessageIter array;
191 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
193 gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_cb, &array);
195 dbus_message_iter_close_container(iter, &array);
200 static void read_check_cb(struct gatt_db_attribute *attrib, int err,
201 const uint8_t *value, size_t length,
204 gboolean *ret = user_data;
214 static gboolean descriptor_value_exists(const GDBusPropertyTable *property,
217 struct descriptor *desc = data;
220 gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_check_cb, &ret);
225 static int parse_value_arg(DBusMessageIter *iter, uint8_t **value, int *len)
227 DBusMessageIter array;
229 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
232 dbus_message_iter_recurse(iter, &array);
233 dbus_message_iter_get_fixed_array(&array, value, len);
238 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
239 static int parse_type_value_arg(DBusMessageIter *iter, uint8_t *type, uint8_t **value,
242 DBusMessageIter array;
244 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BYTE)
246 dbus_message_iter_get_basic(iter, type);
247 dbus_message_iter_next(iter);
248 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
251 dbus_message_iter_recurse(iter, &array);
252 dbus_message_iter_get_fixed_array(&array, value, len);
258 static void async_dbus_op_free(void *data)
260 struct async_dbus_op *op = data;
262 queue_destroy(op->msgs, (void *)dbus_message_unref);
267 static struct async_dbus_op *async_dbus_op_ref(struct async_dbus_op *op)
269 __sync_fetch_and_add(&op->ref_count, 1);
274 static void async_dbus_op_unref(void *data)
276 struct async_dbus_op *op = data;
278 if (__sync_sub_and_fetch(&op->ref_count, 1))
281 async_dbus_op_free(op);
284 static void message_append_byte_array(DBusMessage *msg, const uint8_t *bytes,
287 DBusMessageIter iter, array;
289 dbus_message_iter_init_append(msg, &iter);
290 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "y", &array);
291 dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, &bytes,
293 dbus_message_iter_close_container(&iter, &array);
296 static DBusMessage *create_gatt_dbus_error(DBusMessage *msg, uint8_t att_ecode)
298 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
299 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
300 "Operation failed with ATT error: 0x%02x",
304 case BT_ATT_ERROR_READ_NOT_PERMITTED:
305 return btd_error_not_permitted(msg, "Read not permitted");
306 case BT_ATT_ERROR_WRITE_NOT_PERMITTED:
307 return btd_error_not_permitted(msg, "Write not permitted");
308 case BT_ATT_ERROR_AUTHENTICATION:
309 case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION:
310 case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE:
311 return btd_error_not_permitted(msg, "Not paired");
312 case BT_ATT_ERROR_INVALID_OFFSET:
313 return btd_error_invalid_args_str(msg, "Invalid offset");
314 case BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN:
315 return btd_error_invalid_args_str(msg, "Invalid Length");
316 case BT_ATT_ERROR_AUTHORIZATION:
317 return btd_error_not_authorized(msg);
318 case BT_ATT_ERROR_REQUEST_NOT_SUPPORTED:
319 return btd_error_not_supported(msg);
321 return btd_error_failed(msg, "Operation failed");
323 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
324 "Operation failed with ATT error: 0x%02x",
332 static void write_descriptor_cb(struct gatt_db_attribute *attr, int err,
335 struct descriptor *desc = user_data;
340 g_dbus_emit_property_changed(btd_get_dbus_connection(), desc->path,
341 GATT_DESCRIPTOR_IFACE, "Value");
344 static void async_dbus_op_reply(struct async_dbus_op *op, int err,
345 const uint8_t *value, ssize_t length)
347 const struct queue_entry *entry;
352 for (entry = queue_get_entries(op->msgs); entry; entry = entry->next) {
353 DBusMessage *msg = entry->data;
356 reply = err > 0 ? create_gatt_dbus_error(msg, err) :
357 btd_error_failed(msg, strerror(-err));
361 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
363 error("Failed to allocate D-Bus message reply");
368 message_append_byte_array(reply, value, length);
371 g_dbus_send_message(btd_get_dbus_connection(), reply);
375 static void read_op_cb(struct gatt_db_attribute *attrib, int err,
376 const uint8_t *value, size_t length,
379 struct async_dbus_op *op = user_data;
381 async_dbus_op_reply(op, err, value, length);
384 static void desc_read_cb(bool success, uint8_t att_ecode,
385 const uint8_t *value, uint16_t length,
388 struct async_dbus_op *op = user_data;
389 struct descriptor *desc = op->data;
395 gatt_db_attribute_reset(desc->attr);
397 if (!gatt_db_attribute_write(desc->attr, op->offset, value, length, 0,
398 NULL, write_descriptor_cb, desc)) {
399 error("Failed to store attribute");
400 att_ecode = BT_ATT_ERROR_UNLIKELY;
404 /* Read the stored data from db */
405 if (!gatt_db_attribute_read(desc->attr, op->offset, 0, NULL, read_op_cb,
407 error("Failed to read database");
408 att_ecode = BT_ATT_ERROR_UNLIKELY;
412 desc->read_op = NULL;
417 async_dbus_op_reply(op, att_ecode, NULL, 0);
418 desc->read_op = NULL;
421 static int parse_options(DBusMessageIter *iter, uint16_t *offset,
424 DBusMessageIter dict;
426 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
429 dbus_message_iter_recurse(iter, &dict);
431 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
433 DBusMessageIter value, entry;
436 dbus_message_iter_recurse(&dict, &entry);
437 dbus_message_iter_get_basic(&entry, &key);
439 dbus_message_iter_next(&entry);
440 dbus_message_iter_recurse(&entry, &value);
442 var = dbus_message_iter_get_arg_type(&value);
443 if (strcasecmp(key, "offset") == 0) {
444 if (var != DBUS_TYPE_UINT16)
446 dbus_message_iter_get_basic(&value, offset);
449 if (type && strcasecmp(key, "type") == 0) {
450 if (var != DBUS_TYPE_STRING)
452 dbus_message_iter_get_basic(&value, type);
455 dbus_message_iter_next(&dict);
461 static struct async_dbus_op *async_dbus_op_new(DBusMessage *msg, void *data)
463 struct async_dbus_op *op;
465 op = new0(struct async_dbus_op, 1);
466 op->msgs = queue_new();
467 queue_push_tail(op->msgs, dbus_message_ref(msg));
473 static struct async_dbus_op *read_value(struct bt_gatt_client *gatt,
474 DBusMessage *msg, uint16_t handle,
476 bt_gatt_client_read_callback_t callback,
479 struct async_dbus_op *op;
481 op = async_dbus_op_new(msg, data);
484 op->id = bt_gatt_client_read_long_value(gatt, handle, offset, callback,
485 async_dbus_op_ref(op),
486 async_dbus_op_unref);
490 async_dbus_op_free(op);
495 static DBusMessage *descriptor_read_value(DBusConnection *conn,
496 DBusMessage *msg, void *user_data)
498 struct descriptor *desc = user_data;
499 struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
500 DBusMessageIter iter;
504 return btd_error_failed(msg, "Not connected");
506 dbus_message_iter_init(msg, &iter);
508 if (parse_options(&iter, &offset, NULL))
509 return btd_error_invalid_args(msg);
512 if (desc->read_op->offset != offset)
513 return btd_error_in_progress(msg);
514 queue_push_tail(desc->read_op->msgs, dbus_message_ref(msg));
518 desc->read_op = read_value(gatt, msg, desc->handle, offset,
521 return btd_error_failed(msg, "Failed to send read request");
526 static void write_result_cb(bool success, bool reliable_error,
527 uint8_t att_ecode, void *user_data)
529 struct async_dbus_op *op = user_data;
532 if (op->complete && !op->complete(op->data)) {
545 async_dbus_op_reply(op, err, NULL, -1);
548 static void write_cb(bool success, uint8_t att_ecode, void *user_data)
550 write_result_cb(success, false, att_ecode, user_data);
553 static struct async_dbus_op *start_long_write(DBusMessage *msg, uint16_t handle,
554 struct bt_gatt_client *gatt,
555 bool reliable, const uint8_t *value,
556 size_t value_len, uint16_t offset,
558 async_dbus_op_complete_t complete)
560 struct async_dbus_op *op;
562 op = async_dbus_op_new(msg, data);
563 op->complete = complete;
566 op->id = bt_gatt_client_write_long_value(gatt, reliable, handle, offset,
572 async_dbus_op_free(op);
579 static struct async_dbus_op *start_write_request(DBusMessage *msg,
581 struct bt_gatt_client *gatt,
582 const uint8_t *value, size_t value_len,
584 async_dbus_op_complete_t complete)
586 struct async_dbus_op *op;
588 op = async_dbus_op_new(msg, data);
589 op->complete = complete;
591 op->id = bt_gatt_client_write_value(gatt, handle, value, value_len,
595 async_dbus_op_free(op);
601 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
602 static struct async_dbus_op *start_write_cmd(DBusMessage *msg, uint16_t handle,
603 struct bt_gatt_client *gatt, bool signed_write,
604 const uint8_t *value, size_t value_len,
605 void *data, async_dbus_op_complete_t complete)
607 struct async_dbus_op *op;
609 op = async_dbus_op_new(msg, data);
610 op->complete = complete;
612 op->id = bt_gatt_client_write_without_response_async(gatt, handle,
613 signed_write, value, value_len,
614 write_cb, op, async_dbus_op_free);
617 async_dbus_op_free(op);
625 static bool desc_write_complete(void *data)
627 struct descriptor *desc = data;
629 desc->write_op = NULL;
632 * The descriptor might have been unregistered during the read. Return
638 static DBusMessage *descriptor_write_value(DBusConnection *conn,
639 DBusMessage *msg, void *user_data)
641 struct descriptor *desc = user_data;
642 struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
643 DBusMessageIter iter;
644 uint8_t *value = NULL;
649 return btd_error_failed(msg, "Not connected");
652 return btd_error_in_progress(msg);
654 dbus_message_iter_init(msg, &iter);
656 if (parse_value_arg(&iter, &value, &value_len))
657 return btd_error_invalid_args(msg);
659 dbus_message_iter_next(&iter);
661 if (parse_options(&iter, &offset, NULL))
662 return btd_error_invalid_args(msg);
665 * Don't allow writing to Client Characteristic Configuration
666 * descriptors. We achieve this through the StartNotify and StopNotify
667 * methods on GattCharacteristic1.
669 if (uuid_cmp(&desc->uuid, GATT_CLIENT_CHARAC_CFG_UUID))
670 return btd_error_not_permitted(msg, "Write not permitted");
673 * Based on the value length and the MTU, either use a write or a long
676 if (value_len <= bt_gatt_client_get_mtu(gatt) - 3 && !offset)
677 desc->write_op = start_write_request(msg, desc->handle,
680 desc_write_complete);
682 desc->write_op = start_long_write(msg, desc->handle, gatt,
684 value_len, offset, desc,
685 desc_write_complete);
688 return btd_error_failed(msg, "Failed to initiate write");
693 static const GDBusPropertyTable descriptor_properties[] = {
694 { "UUID", "s", descriptor_get_uuid },
695 { "Characteristic", "o", descriptor_get_characteristic, },
696 { "Value", "ay", descriptor_get_value, NULL, descriptor_value_exists },
700 static const GDBusMethodTable descriptor_methods[] = {
701 { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
702 GDBUS_ARGS({ "value", "ay" }),
703 descriptor_read_value) },
704 { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
705 { "options", "a{sv}" }),
707 descriptor_write_value) },
711 static void descriptor_free(void *data)
713 struct descriptor *desc = data;
719 static struct descriptor *descriptor_create(struct gatt_db_attribute *attr,
720 struct characteristic *chrc)
722 struct descriptor *desc;
724 desc = new0(struct descriptor, 1);
727 desc->handle = gatt_db_attribute_get_handle(attr);
729 bt_uuid_to_uuid128(gatt_db_attribute_get_type(attr), &desc->uuid);
731 desc->path = g_strdup_printf("%s/desc%04x", chrc->path, desc->handle);
733 if (!g_dbus_register_interface(btd_get_dbus_connection(), desc->path,
734 GATT_DESCRIPTOR_IFACE,
735 descriptor_methods, NULL,
736 descriptor_properties,
737 desc, descriptor_free)) {
738 error("Unable to register GATT descriptor with handle 0x%04x",
740 descriptor_free(desc);
745 DBG("Exported GATT characteristic descriptor: %s", desc->path);
747 if (uuid_cmp(&desc->uuid, GATT_CHARAC_EXT_PROPER_UUID))
748 chrc->ext_props_handle = desc->handle;
753 static void unregister_descriptor(void *data)
755 struct descriptor *desc = data;
756 struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
758 DBG("Removing GATT descriptor: %s", desc->path);
761 bt_gatt_client_cancel(gatt, desc->read_op->id);
764 bt_gatt_client_cancel(gatt, desc->write_op->id);
768 g_dbus_unregister_interface(btd_get_dbus_connection(), desc->path,
769 GATT_DESCRIPTOR_IFACE);
772 static gboolean characteristic_get_uuid(const GDBusPropertyTable *property,
773 DBusMessageIter *iter, void *data)
775 char uuid[MAX_LEN_UUID_STR + 1];
776 const char *ptr = uuid;
777 struct characteristic *chrc = data;
779 bt_uuid_to_string(&chrc->uuid, uuid, sizeof(uuid));
780 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
785 static gboolean characteristic_get_service(const GDBusPropertyTable *property,
786 DBusMessageIter *iter, void *data)
788 struct characteristic *chrc = data;
789 const char *str = chrc->service->path;
791 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &str);
796 static gboolean characteristic_get_value(const GDBusPropertyTable *property,
797 DBusMessageIter *iter, void *data)
799 struct characteristic *chrc = data;
800 DBusMessageIter array;
802 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
804 gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_cb, &array);
806 dbus_message_iter_close_container(iter, &array);
811 static gboolean characteristic_value_exists(const GDBusPropertyTable *property,
814 struct characteristic *chrc = data;
817 gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_check_cb, &ret);
822 static gboolean characteristic_get_notifying(const GDBusPropertyTable *property,
823 DBusMessageIter *iter, void *data)
825 struct characteristic *chrc = data;
826 dbus_bool_t notifying = chrc->notifying ? TRUE : FALSE;
828 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, ¬ifying);
834 characteristic_notifying_exists(const GDBusPropertyTable *property, void *data)
836 struct characteristic *chrc = data;
838 return (chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
839 chrc->props & BT_GATT_CHRC_PROP_INDICATE);
842 struct chrc_prop_data {
847 static struct chrc_prop_data chrc_props[] = {
848 /* Default Properties */
849 { BT_GATT_CHRC_PROP_BROADCAST, "broadcast" },
850 { BT_GATT_CHRC_PROP_READ, "read" },
851 { BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP, "write-without-response" },
852 { BT_GATT_CHRC_PROP_WRITE, "write" },
853 { BT_GATT_CHRC_PROP_NOTIFY, "notify" },
854 { BT_GATT_CHRC_PROP_INDICATE, "indicate" },
855 { BT_GATT_CHRC_PROP_AUTH, "authenticated-signed-writes" },
856 { BT_GATT_CHRC_PROP_EXT_PROP, "extended-properties" }
859 static struct chrc_prop_data chrc_ext_props[] = {
860 /* Extended Properties */
861 { BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE, "reliable-write" },
862 { BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX, "writable-auxiliaries" }
865 static gboolean characteristic_get_flags(const GDBusPropertyTable *property,
866 DBusMessageIter *iter, void *data)
868 struct characteristic *chrc = data;
869 DBusMessageIter array;
872 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
874 for (i = 0; i < NELEM(chrc_props); i++) {
875 if (chrc->props & chrc_props[i].prop)
876 dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
880 for (i = 0; i < NELEM(chrc_ext_props); i++) {
881 if (chrc->ext_props & chrc_ext_props[i].prop)
882 dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
883 &chrc_ext_props[i].str);
886 dbus_message_iter_close_container(iter, &array);
892 characteristic_get_write_acquired(const GDBusPropertyTable *property,
893 DBusMessageIter *iter, void *data)
895 struct characteristic *chrc = data;
896 dbus_bool_t locked = chrc->write_io ? TRUE : FALSE;
898 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &locked);
904 characteristic_write_acquired_exists(const GDBusPropertyTable *property,
907 struct characteristic *chrc = data;
909 return (chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP);
913 characteristic_get_notify_acquired(const GDBusPropertyTable *property,
914 DBusMessageIter *iter, void *data)
916 struct characteristic *chrc = data;
917 dbus_bool_t locked = chrc->notify_io ? TRUE : FALSE;
919 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &locked);
925 characteristic_notify_acquired_exists(const GDBusPropertyTable *property,
928 struct characteristic *chrc = data;
930 return (chrc->props & BT_GATT_CHRC_PROP_NOTIFY);
933 static gboolean characteristic_get_mtu(const GDBusPropertyTable *property,
934 DBusMessageIter *iter, void *data)
936 struct characteristic *chrc = data;
937 struct bt_gatt_client *gatt = chrc->service->client->gatt;
941 att = bt_gatt_client_get_att(gatt);
942 mtu = att ? bt_att_get_mtu(att) : BT_ATT_DEFAULT_LE_MTU;
944 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &mtu);
949 static gboolean characteristic_mtu_exists(const GDBusPropertyTable *property,
952 struct characteristic *chrc = data;
954 return chrc->service->client->gatt ? TRUE : FALSE;
957 static void write_characteristic_cb(struct gatt_db_attribute *attr, int err,
960 struct characteristic *chrc = user_data;
965 g_dbus_emit_property_changed_full(btd_get_dbus_connection(),
966 chrc->path, GATT_CHARACTERISTIC_IFACE,
967 "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH);
971 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
972 static void notify_characteristic_cb(struct gatt_db_attribute *attr, int err,
976 error("Failed to notify_characteristic_cb : %d", err);
982 static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
983 uint16_t length, void *user_data)
985 struct async_dbus_op *op = user_data;
986 struct characteristic *chrc = op->data;
992 gatt_db_attribute_reset(chrc->attr);
994 if (!gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0,
995 NULL, write_characteristic_cb, chrc)) {
996 error("Failed to store attribute");
997 att_ecode = BT_ATT_ERROR_UNLIKELY;
1001 /* Read the stored data from db */
1002 if (!gatt_db_attribute_read(chrc->attr, op->offset, 0, NULL, read_op_cb,
1004 error("Failed to read database");
1005 att_ecode = BT_ATT_ERROR_UNLIKELY;
1009 chrc->read_op = NULL;
1014 async_dbus_op_reply(op, att_ecode, NULL, 0);
1015 chrc->read_op = NULL;
1018 static DBusMessage *characteristic_read_value(DBusConnection *conn,
1019 DBusMessage *msg, void *user_data)
1021 struct characteristic *chrc = user_data;
1022 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1023 DBusMessageIter iter;
1024 uint16_t offset = 0;
1027 return btd_error_failed(msg, "Not connected");
1029 dbus_message_iter_init(msg, &iter);
1031 if (parse_options(&iter, &offset, NULL))
1032 return btd_error_invalid_args(msg);
1034 if (chrc->read_op) {
1035 if (chrc->read_op->offset != offset)
1036 return btd_error_in_progress(msg);
1037 queue_push_tail(chrc->read_op->msgs, dbus_message_ref(msg));
1041 chrc->read_op = read_value(gatt, msg, chrc->value_handle, offset,
1042 chrc_read_cb, chrc);
1044 return btd_error_failed(msg, "Failed to send read request");
1049 static bool chrc_write_complete(void *data)
1051 struct characteristic *chrc = data;
1053 chrc->write_op = NULL;
1056 * The characteristic might have been unregistered during the read.
1059 return !!chrc->service;
1062 static DBusMessage *characteristic_write_value(DBusConnection *conn,
1063 DBusMessage *msg, void *user_data)
1065 struct characteristic *chrc = user_data;
1066 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1067 DBusMessageIter iter;
1068 uint8_t *value = NULL;
1070 bool supported = false;
1071 uint16_t offset = 0;
1072 const char *type = NULL;
1075 return btd_error_failed(msg, "Not connected");
1078 return btd_error_not_permitted(msg, "Write acquired");
1081 return btd_error_in_progress(msg);
1083 dbus_message_iter_init(msg, &iter);
1085 if (parse_value_arg(&iter, &value, &value_len))
1086 return btd_error_invalid_args(msg);
1088 dbus_message_iter_next(&iter);
1090 if (parse_options(&iter, &offset, &type))
1091 return btd_error_invalid_args(msg);
1094 * Decide which write to use based on characteristic properties. For now
1095 * we don't perform signed writes since gatt-client doesn't support them
1096 * and the user can always encrypt the through pairing. The procedure to
1097 * use is determined based on the following priority:
1099 * * "reliable-write" property set -> reliable long-write.
1100 * * "write" property set -> write request.
1101 * - If value is larger than MTU - 3: long-write
1102 * * "write-without-response" property set -> write command.
1104 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
1105 if ((!type && (chrc->ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE))
1106 || (type && !strcasecmp(type, "reliable"))) {
1108 chrc->write_op = start_long_write(msg, chrc->value_handle, gatt,
1109 true, value, value_len, offset,
1110 chrc, chrc_write_complete);
1116 if ((!type && chrc->props & BT_GATT_CHRC_PROP_WRITE) ||
1117 (type && !strcasecmp(type, "request"))) {
1121 mtu = bt_gatt_client_get_mtu(gatt);
1123 return btd_error_failed(msg, "No ATT transport");
1125 if (value_len <= mtu - 3 && !offset)
1126 chrc->write_op = start_write_request(msg,
1128 gatt, value, value_len,
1129 chrc, chrc_write_complete);
1131 chrc->write_op = start_long_write(msg,
1132 chrc->value_handle, gatt,
1133 false, value, value_len, offset,
1134 chrc, chrc_write_complete);
1140 if ((type && strcasecmp(type, "command")) || offset || (!type &&
1141 !(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP)))
1146 if (bt_gatt_client_write_without_response(gatt,
1148 chrc->props & BT_GATT_CHRC_PROP_AUTH,
1150 return dbus_message_new_method_return(msg);
1154 return btd_error_failed(msg, "Failed to initiate write");
1156 return btd_error_not_supported(msg);
1159 static bool sock_read(struct io *io, void *user_data)
1161 struct characteristic *chrc = user_data;
1162 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1166 int fd = io_get_fd(io);
1170 iov.iov_len = sizeof(buf);
1172 memset(&msg, 0, sizeof(msg));
1176 bytes_read = recvmsg(fd, &msg, MSG_DONTWAIT);
1177 if (bytes_read < 0) {
1178 error("recvmsg: %s", strerror(errno));
1182 if (!gatt || bytes_read == 0)
1185 bt_gatt_client_write_without_response(gatt, chrc->value_handle,
1186 chrc->props & BT_GATT_CHRC_PROP_AUTH,
1192 static void sock_io_destroy(struct sock_io *io)
1195 io->destroy(io->data);
1198 dbus_message_unref(io->msg);
1204 static void destroy_sock(struct characteristic *chrc,
1207 queue_remove(chrc->service->client->ios, io);
1209 if (chrc->write_io && io == chrc->write_io->io) {
1210 sock_io_destroy(chrc->write_io);
1211 chrc->write_io = NULL;
1212 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1214 GATT_CHARACTERISTIC_IFACE,
1216 } else if (chrc->notify_io) {
1217 sock_io_destroy(chrc->notify_io);
1218 chrc->notify_io = NULL;
1219 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1221 GATT_CHARACTERISTIC_IFACE,
1226 static bool sock_hup(struct io *io, void *user_data)
1228 struct characteristic *chrc = user_data;
1230 DBG("%s: io %p", chrc->path, io);
1232 destroy_sock(chrc, io);
1237 static DBusMessage *create_sock(struct characteristic *chrc,
1240 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1247 if (!gatt || !bt_gatt_client_is_ready(gatt))
1248 return btd_error_failed(msg, "Not connected");
1250 if (socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC,
1252 return btd_error_failed(msg, strerror(errno));
1254 dir = dbus_message_has_member(msg, "AcquireWrite");
1256 io = io_new(fds[!dir]);
1260 return btd_error_failed(msg, strerror(EIO));
1263 io_set_close_on_destroy(io, true);
1265 if (!io_set_read_handler(io, sock_read, chrc, NULL))
1268 if (!io_set_disconnect_handler(io, sock_hup, chrc, NULL))
1271 mtu = bt_gatt_client_get_mtu(gatt);
1273 reply = g_dbus_create_reply(msg, DBUS_TYPE_UNIX_FD, &fds[dir],
1274 DBUS_TYPE_UINT16, &mtu,
1280 chrc->write_io->io = io;
1281 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1283 GATT_CHARACTERISTIC_IFACE,
1286 chrc->notify_io->io = io;
1287 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1289 GATT_CHARACTERISTIC_IFACE,
1293 queue_push_tail(chrc->service->client->ios, io);
1295 DBG("%s: sender %s io %p", dbus_message_get_member(msg),
1296 dbus_message_get_sender(msg), io);
1303 return btd_error_failed(msg, strerror(EIO));
1306 static void characteristic_ready(bool success, uint8_t ecode, void *user_data)
1308 struct characteristic *chrc = user_data;
1313 if (chrc->write_io && chrc->write_io->msg) {
1314 reply = create_sock(chrc, chrc->write_io->msg);
1316 g_dbus_send_message(btd_get_dbus_connection(), reply);
1318 dbus_message_unref(chrc->write_io->msg);
1319 chrc->write_io->msg = NULL;
1322 if (chrc->notify_io && chrc->notify_io->msg) {
1323 reply = create_sock(chrc, chrc->notify_io->msg);
1325 g_dbus_send_message(btd_get_dbus_connection(), reply);
1327 dbus_message_unref(chrc->notify_io->msg);
1328 chrc->notify_io->msg = NULL;
1332 static DBusMessage *characteristic_acquire_write(DBusConnection *conn,
1333 DBusMessage *msg, void *user_data)
1335 struct characteristic *chrc = user_data;
1336 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1339 return btd_error_failed(msg, "Not connected");
1342 return btd_error_not_permitted(msg, "Write acquired");
1344 if (!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP))
1345 return btd_error_not_supported(msg);
1347 chrc->write_io = new0(struct sock_io, 1);
1349 if (!bt_gatt_client_is_ready(gatt)) {
1350 /* GATT not ready, wait until it becomes ready */
1351 if (!chrc->ready_id)
1352 chrc->ready_id = bt_gatt_client_ready_register(gatt,
1353 characteristic_ready,
1355 chrc->write_io->msg = dbus_message_ref(msg);
1359 return create_sock(chrc, msg);
1362 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1363 static DBusMessage *characteristic_write_value_by_type(DBusConnection *conn,
1364 DBusMessage *msg, void *user_data)
1366 struct characteristic *chrc = user_data;
1367 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1368 DBusMessageIter iter;
1369 uint8_t *value = NULL;
1371 bool supported = false;
1372 uint8_t write_type = 0;
1373 uint16_t offset = 0;
1376 return btd_error_failed(msg, "Not connected");
1379 return btd_error_in_progress(msg);
1381 dbus_message_iter_init(msg, &iter);
1383 if (parse_type_value_arg(&iter, &write_type, &value, &value_len))
1384 return btd_error_invalid_args(msg);
1386 if (parse_options(&iter, &offset,NULL))
1387 return btd_error_invalid_args(msg);
1389 if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_WRITE) {
1393 mtu = bt_gatt_client_get_mtu(gatt);
1395 return btd_error_failed(msg, "No ATT transport");
1397 if (value_len <= mtu - 3 && !offset)
1398 chrc->write_op = start_write_request(msg,
1400 gatt, value, value_len,
1401 chrc, chrc_write_complete);
1403 chrc->write_op = start_long_write(msg,
1404 chrc->value_handle, gatt,
1405 false, value, value_len, offset,
1406 chrc, chrc_write_complete);
1410 } else if ((write_type & chrc->props) ==
1411 BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) {
1413 chrc->write_op = start_write_cmd(msg, chrc->value_handle, gatt,
1414 false, value, value_len,
1415 chrc, chrc_write_complete);
1418 } else if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_AUTH) {
1420 chrc->write_op = start_write_cmd(msg, chrc->value_handle, gatt,
1421 true, value, value_len,
1422 chrc, chrc_write_complete);
1428 return btd_error_failed(msg, "Failed to initiate write");
1430 return btd_error_not_supported(msg);
1434 struct notify_client {
1435 struct characteristic *chrc;
1439 unsigned int notify_id;
1442 static void notify_client_free(struct notify_client *client)
1444 DBG("owner %s", client->owner);
1446 g_dbus_remove_watch(btd_get_dbus_connection(), client->watch);
1447 bt_gatt_client_unregister_notify(client->chrc->service->client->gatt,
1449 free(client->owner);
1453 static void notify_client_unref(void *data)
1455 struct notify_client *client = data;
1457 DBG("owner %s", client->owner);
1459 if (__sync_sub_and_fetch(&client->ref_count, 1))
1462 notify_client_free(client);
1465 static struct notify_client *notify_client_ref(struct notify_client *client)
1467 DBG("owner %s", client->owner);
1469 __sync_fetch_and_add(&client->ref_count, 1);
1474 static bool match_notifying(const void *a, const void *b)
1476 const struct notify_client *client = a;
1478 return !!client->notify_id;
1481 static void update_notifying(struct characteristic *chrc)
1483 if (!chrc->notifying)
1486 if (queue_find(chrc->notify_clients, match_notifying, NULL))
1489 chrc->notifying = false;
1491 g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
1492 GATT_CHARACTERISTIC_IFACE,
1496 static void notify_client_disconnect(DBusConnection *conn, void *user_data)
1498 struct notify_client *client = user_data;
1499 struct characteristic *chrc = client->chrc;
1501 DBG("owner %s", client->owner);
1503 queue_remove(chrc->notify_clients, client);
1504 queue_remove(chrc->service->client->all_notify_clients, client);
1506 update_notifying(chrc);
1508 notify_client_unref(client);
1511 static struct notify_client *notify_client_create(struct characteristic *chrc,
1514 struct notify_client *client;
1516 client = new0(struct notify_client, 1);
1517 client->chrc = chrc;
1518 client->owner = strdup(owner);
1519 if (!client->owner) {
1524 client->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
1525 owner, notify_client_disconnect,
1527 if (!client->watch) {
1528 free(client->owner);
1533 return notify_client_ref(client);
1536 static bool match_notify_sender(const void *a, const void *b)
1538 const struct notify_client *client = a;
1539 const char *sender = b;
1541 return strcmp(client->owner, sender) == 0;
1544 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1545 void gatt_characteristic_value_changed(struct notify_client *client, const uint8_t *data, uint16_t data_len, void *user_data)
1547 struct characteristic *chrc = user_data;
1548 char *chrc_path = strdup(chrc->path);
1549 dbus_int32_t result = 0;
1551 g_dbus_emit_signal_to_dest(btd_get_dbus_connection(),
1552 client->owner, chrc_path,
1553 GATT_CHARACTERISTIC_IFACE, "GattValueChanged",
1554 DBUS_TYPE_INT32, &result,
1555 DBUS_TYPE_STRING, &chrc_path,
1556 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, data_len,
1565 static void notify_cb(uint16_t value_handle, const uint8_t *value,
1566 uint16_t length, void *user_data)
1568 struct async_dbus_op *op = user_data;
1569 struct notify_client *client = op->data;
1570 struct characteristic *chrc = client->chrc;
1573 * Even if the value didn't change, we want to send a PropertiesChanged
1574 * signal so that we propagate the notification/indication to
1577 gatt_db_attribute_reset(chrc->attr);
1578 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1579 gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
1580 notify_characteristic_cb, chrc);
1582 gatt_characteristic_value_changed(client, value, length, chrc);
1584 gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
1585 write_characteristic_cb, chrc);
1589 static void create_notify_reply(struct async_dbus_op *op, bool success,
1597 err = att_ecode ? att_ecode : -ENOENT;
1599 async_dbus_op_reply(op, err, NULL, -1);
1602 static void register_notify_cb(uint16_t att_ecode, void *user_data)
1604 struct async_dbus_op *op = user_data;
1605 struct notify_client *client = op->data;
1606 struct characteristic *chrc = client->chrc;
1609 queue_remove(chrc->notify_clients, client);
1610 queue_remove(chrc->service->client->all_notify_clients, client);
1611 notify_client_free(client);
1613 create_notify_reply(op, false, att_ecode);
1618 if (!chrc->notifying) {
1619 chrc->notifying = true;
1620 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1621 chrc->path, GATT_CHARACTERISTIC_IFACE,
1625 create_notify_reply(op, true, 0);
1628 static void notify_io_cb(uint16_t value_handle, const uint8_t *value,
1629 uint16_t length, void *user_data)
1633 struct notify_client *client = user_data;
1634 struct characteristic *chrc = client->chrc;
1637 /* Drop notification if the pipe is not ready */
1638 if (!chrc->notify_io || !chrc->notify_io->io)
1641 iov.iov_base = (void *) value;
1642 iov.iov_len = length;
1644 memset(&msg, 0, sizeof(msg));
1648 err = sendmsg(io_get_fd(chrc->notify_io->io), &msg, MSG_NOSIGNAL);
1650 error("sendmsg: %s", strerror(errno));
1653 static void register_notify_io_cb(uint16_t att_ecode, void *user_data)
1655 struct notify_client *client = user_data;
1656 struct characteristic *chrc = client->chrc;
1657 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1660 queue_remove(chrc->notify_clients, client);
1661 notify_client_free(client);
1665 if (!bt_gatt_client_is_ready(gatt)) {
1666 if (!chrc->ready_id)
1667 chrc->ready_id = bt_gatt_client_ready_register(gatt,
1668 characteristic_ready,
1673 characteristic_ready(true, 0, chrc);
1676 static void notify_io_destroy(void *data)
1678 struct notify_client *client = data;
1680 if (queue_remove(client->chrc->notify_clients, client))
1681 notify_client_unref(client);
1684 static DBusMessage *characteristic_acquire_notify(DBusConnection *conn,
1685 DBusMessage *msg, void *user_data)
1687 struct characteristic *chrc = user_data;
1688 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1689 const char *sender = dbus_message_get_sender(msg);
1690 struct notify_client *client;
1693 return btd_error_failed(msg, "Not connected");
1695 if (chrc->notify_io)
1696 return btd_error_not_permitted(msg, "Notify acquired");
1698 /* Each client can only have one active notify session. */
1699 if (!queue_isempty(chrc->notify_clients))
1700 return btd_error_in_progress(msg);
1702 if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY))
1703 return btd_error_not_supported(msg);
1705 client = notify_client_create(chrc, sender);
1707 return btd_error_failed(msg, "Failed allocate notify session");
1709 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1710 chrc->notify_io = new0(struct sock_io, 1);
1711 chrc->notify_io->data = client;
1712 chrc->notify_io->msg = dbus_message_ref(msg);
1713 chrc->notify_io->destroy = notify_io_destroy;
1715 client->notify_id = bt_gatt_client_register_notify(gatt,
1717 register_notify_io_cb,
1720 if (!client->notify_id) {
1721 notify_client_unref(client);
1722 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1723 dbus_message_unref(chrc->notify_io->msg);
1724 g_free(chrc->notify_io);
1725 chrc->notify_io = NULL;
1727 return btd_error_failed(msg, "Failed to subscribe");
1730 queue_push_tail(chrc->notify_clients, client);
1732 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
1733 chrc->notify_io = new0(struct sock_io, 1);
1734 chrc->notify_io->data = client;
1735 chrc->notify_io->msg = dbus_message_ref(msg);
1736 chrc->notify_io->destroy = notify_io_destroy;
1742 static DBusMessage *characteristic_start_notify(DBusConnection *conn,
1743 DBusMessage *msg, void *user_data)
1745 struct characteristic *chrc = user_data;
1746 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1747 const char *sender = dbus_message_get_sender(msg);
1748 struct async_dbus_op *op;
1749 struct notify_client *client;
1750 struct btd_device *device = chrc->service->client->device;
1752 if (device_is_disconnecting(device)) {
1753 error("Device is disconnecting. StartNotify is not allowed.");
1754 return btd_error_not_connected(msg);
1757 if (chrc->notify_io)
1758 return btd_error_not_permitted(msg, "Notify acquired");
1760 if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
1761 chrc->props & BT_GATT_CHRC_PROP_INDICATE))
1762 return btd_error_not_supported(msg);
1764 /* Each client can only have one active notify session. */
1765 client = queue_find(chrc->notify_clients, match_notify_sender, sender);
1767 return client->notify_id ?
1768 g_dbus_create_reply(msg, DBUS_TYPE_INVALID) :
1769 btd_error_in_progress(msg);
1771 client = notify_client_create(chrc, sender);
1773 return btd_error_failed(msg, "Failed allocate notify session");
1775 queue_push_tail(chrc->notify_clients, client);
1776 queue_push_tail(chrc->service->client->all_notify_clients, client);
1779 * If the device is currently not connected, return success. We will
1780 * automatically try and register all clients when a GATT client becomes
1786 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1791 * Clean up and respond with an error instead of timing out to
1792 * avoid any ambiguities.
1794 error("Failed to construct D-Bus message reply");
1798 op = async_dbus_op_new(msg, client);
1800 client->notify_id = bt_gatt_client_register_notify(gatt,
1802 register_notify_cb, notify_cb,
1803 op, async_dbus_op_free);
1804 if (client->notify_id)
1807 async_dbus_op_free(op);
1810 queue_remove(chrc->notify_clients, client);
1811 queue_remove(chrc->service->client->all_notify_clients, client);
1813 /* Directly free the client */
1814 notify_client_free(client);
1816 return btd_error_failed(msg, "Failed to register notify session");
1819 static DBusMessage *characteristic_stop_notify(DBusConnection *conn,
1820 DBusMessage *msg, void *user_data)
1822 struct characteristic *chrc = user_data;
1823 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1824 const char *sender = dbus_message_get_sender(msg);
1825 struct notify_client *client;
1827 if (chrc->notify_io) {
1828 destroy_sock(chrc, chrc->notify_io->io);
1829 return dbus_message_new_method_return(msg);
1833 client = queue_remove_if(chrc->notify_clients, match_notify_sender,
1836 return btd_error_failed(msg, "No notify session started");
1838 queue_remove(chrc->service->client->all_notify_clients, client);
1839 bt_gatt_client_unregister_notify(gatt, client->notify_id);
1840 update_notifying(chrc);
1842 notify_client_unref(client);
1844 return dbus_message_new_method_return(msg);
1847 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1848 static void append_desc_path(void *data, void *user_data)
1850 struct descriptor *desc = data;
1851 DBusMessageIter *array = user_data;
1853 dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH,
1857 static gboolean characteristic_get_descriptors(
1858 const GDBusPropertyTable *property,
1859 DBusMessageIter *iter, void *data)
1861 struct characteristic *chrc = data;
1862 DBusMessageIter array;
1864 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "o", &array);
1866 queue_foreach(chrc->descs, append_desc_path, &array);
1868 dbus_message_iter_close_container(iter, &array);
1874 static const GDBusPropertyTable characteristic_properties[] = {
1875 { "UUID", "s", characteristic_get_uuid, NULL, NULL },
1876 { "Service", "o", characteristic_get_service, NULL, NULL },
1877 { "Value", "ay", characteristic_get_value, NULL,
1878 characteristic_value_exists },
1879 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1880 { "ChangedValue", "ay", characteristic_get_value, NULL,
1881 characteristic_value_exists },
1883 { "Notifying", "b", characteristic_get_notifying, NULL,
1884 characteristic_notifying_exists },
1885 { "Flags", "as", characteristic_get_flags, NULL, NULL },
1886 { "WriteAcquired", "b", characteristic_get_write_acquired, NULL,
1887 characteristic_write_acquired_exists },
1888 { "NotifyAcquired", "b", characteristic_get_notify_acquired, NULL,
1889 characteristic_notify_acquired_exists },
1890 { "MTU", "q", characteristic_get_mtu, NULL, characteristic_mtu_exists },
1891 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1892 { "Descriptors", "ao", characteristic_get_descriptors },
1897 static const GDBusMethodTable characteristic_methods[] = {
1898 { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
1899 GDBUS_ARGS({ "value", "ay" }),
1900 characteristic_read_value) },
1901 { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
1902 { "options", "a{sv}" }),
1904 characteristic_write_value) },
1905 { GDBUS_ASYNC_METHOD("AcquireWrite",
1906 GDBUS_ARGS({ "options", "a{sv}" }),
1907 GDBUS_ARGS({ "fd", "h" },
1909 characteristic_acquire_write) },
1910 { GDBUS_ASYNC_METHOD("AcquireNotify",
1911 GDBUS_ARGS({ "options", "a{sv}" }),
1912 GDBUS_ARGS({ "fd", "h" },
1914 characteristic_acquire_notify) },
1915 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1916 { GDBUS_ASYNC_METHOD("WriteValuebyType",
1917 GDBUS_ARGS({ "type", "y" }, { "value", "ay" },
1918 { "options", "a{sv}" }),
1920 characteristic_write_value_by_type) },
1922 { GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL,
1923 characteristic_start_notify) },
1924 { GDBUS_METHOD("StopNotify", NULL, NULL,
1925 characteristic_stop_notify) },
1929 static void remove_client(void *data)
1931 struct notify_client *ntfy_client = data;
1932 struct btd_gatt_client *client = ntfy_client->chrc->service->client;
1934 queue_remove(client->all_notify_clients, ntfy_client);
1936 notify_client_unref(ntfy_client);
1939 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1940 static const GDBusSignalTable service_signals[] = {
1941 { GDBUS_SIGNAL("GattServiceAdded",
1942 GDBUS_ARGS({ "Service Path","s"})) },
1945 static const GDBusSignalTable characteristic_signals[] = {
1946 { GDBUS_SIGNAL("GattValueChanged",
1947 GDBUS_ARGS({ "Result", "i"},
1948 { "Characteristic Path","s"},
1949 { "GattData", "ay"})) },
1954 static void characteristic_free(void *data)
1956 struct characteristic *chrc = data;
1957 struct bt_gatt_client *gatt = chrc->service->client->gatt;
1960 /* List should be empty here */
1961 queue_destroy(chrc->descs, NULL);
1963 if (chrc->write_io) {
1964 queue_remove(chrc->service->client->ios, chrc->write_io->io);
1965 sock_io_destroy(chrc->write_io);
1968 if (chrc->notify_io) {
1969 queue_remove(chrc->service->client->ios, chrc->notify_io->io);
1970 sock_io_destroy(chrc->notify_io);
1973 queue_destroy(chrc->notify_clients, remove_client);
1975 att = bt_gatt_client_get_att(gatt);
1977 bt_att_unregister_exchange(att, chrc->exchange_id);
1983 static void att_exchange(uint16_t mtu, void *user_data)
1985 struct characteristic *chrc = user_data;
1987 g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
1988 GATT_CHARACTERISTIC_IFACE, "MTU");
1991 static struct characteristic *characteristic_create(
1992 struct gatt_db_attribute *attr,
1993 struct service *service)
1995 struct characteristic *chrc;
1996 struct bt_gatt_client *gatt = service->client->gatt;
2000 chrc = new0(struct characteristic, 1);
2001 chrc->descs = queue_new();
2002 chrc->notify_clients = queue_new();
2003 chrc->service = service;
2005 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
2006 gatt_db_attribute_get_char_data(attr, &chrc->handle,
2007 &chrc->value_handle,
2012 if (!gatt_db_attribute_get_char_data(attr, &chrc->handle,
2013 &chrc->value_handle,
2017 queue_destroy(chrc->descs, NULL);
2018 queue_destroy(chrc->notify_clients, NULL);
2024 chrc->attr = gatt_db_get_attribute(service->client->db,
2025 chrc->value_handle);
2027 error("Attribute 0x%04x not found", chrc->value_handle);
2028 characteristic_free(chrc);
2032 bt_uuid_to_uuid128(&uuid, &chrc->uuid);
2034 chrc->path = g_strdup_printf("%s/char%04x", service->path,
2037 if (!g_dbus_register_interface(btd_get_dbus_connection(), chrc->path,
2038 GATT_CHARACTERISTIC_IFACE,
2039 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2040 characteristic_methods, characteristic_signals,
2042 characteristic_methods, NULL,
2044 characteristic_properties,
2045 chrc, characteristic_free)) {
2046 error("Unable to register GATT characteristic with handle "
2047 "0x%04x", chrc->handle);
2048 characteristic_free(chrc);
2053 att = bt_gatt_client_get_att(gatt);
2055 chrc->exchange_id = bt_att_register_exchange(att, att_exchange,
2058 DBG("Exported GATT characteristic: %s", chrc->path);
2063 static void unregister_characteristic(void *data)
2065 struct characteristic *chrc = data;
2066 struct bt_gatt_client *gatt = chrc->service->client->gatt;
2068 DBG("Removing GATT characteristic: %s", chrc->path);
2071 bt_gatt_client_cancel(gatt, chrc->read_op->id);
2074 bt_gatt_client_cancel(gatt, chrc->write_op->id);
2076 queue_remove_all(chrc->descs, NULL, NULL, unregister_descriptor);
2078 g_dbus_unregister_interface(btd_get_dbus_connection(), chrc->path,
2079 GATT_CHARACTERISTIC_IFACE);
2082 static gboolean service_get_uuid(const GDBusPropertyTable *property,
2083 DBusMessageIter *iter, void *data)
2085 char uuid[MAX_LEN_UUID_STR + 1];
2086 const char *ptr = uuid;
2087 struct service *service = data;
2089 bt_uuid_to_string(&service->uuid, uuid, sizeof(uuid));
2090 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
2095 static gboolean service_get_device(const GDBusPropertyTable *property,
2096 DBusMessageIter *iter, void *data)
2098 struct service *service = data;
2099 const char *str = device_get_path(service->client->device);
2101 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &str);
2106 static gboolean service_get_primary(const GDBusPropertyTable *property,
2107 DBusMessageIter *iter, void *data)
2109 struct service *service = data;
2110 dbus_bool_t primary;
2112 primary = service->primary ? TRUE : FALSE;
2114 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &primary);
2119 static void append_incl_service_path(void *data, void *user_data)
2121 struct service *incl_service = data;
2122 DBusMessageIter *array = user_data;
2124 dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH,
2125 &incl_service->path);
2128 static gboolean service_get_includes(const GDBusPropertyTable *property,
2129 DBusMessageIter *iter, void *data)
2131 struct service *service = data;
2132 DBusMessageIter array;
2134 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{o}", &array);
2136 queue_foreach(service->incl_services, append_incl_service_path, &array);
2138 dbus_message_iter_close_container(iter, &array);
2144 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2145 static void append_chrc_path(void *data, void *user_data)
2147 struct characteristic *chrc = data;
2148 DBusMessageIter *array = user_data;
2150 dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH,
2154 static gboolean service_get_characteristics(const GDBusPropertyTable *property,
2155 DBusMessageIter *iter, void *data)
2157 struct service *service = data;
2158 DBusMessageIter array;
2160 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "o", &array);
2162 if (service->chrcs_ready)
2163 queue_foreach(service->chrcs, append_chrc_path, &array);
2165 dbus_message_iter_close_container(iter, &array);
2171 static const GDBusPropertyTable service_properties[] = {
2172 { "UUID", "s", service_get_uuid },
2173 { "Device", "o", service_get_device },
2174 { "Primary", "b", service_get_primary },
2175 { "Includes", "ao", service_get_includes },
2176 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2177 { "Characteristics", "ao", service_get_characteristics },
2182 static void service_free(void *data)
2184 struct service *service = data;
2186 queue_destroy(service->chrcs, NULL); /* List should be empty here */
2187 queue_destroy(service->incl_services, NULL);
2188 g_free(service->path);
2192 static struct service *service_create(struct gatt_db_attribute *attr,
2193 struct btd_gatt_client *client)
2195 struct service *service;
2196 const char *device_path = device_get_path(client->device);
2199 service = new0(struct service, 1);
2200 service->chrcs = queue_new();
2201 service->incl_services = queue_new();
2202 service->client = client;
2204 gatt_db_attribute_get_service_data(attr, &service->start_handle,
2205 &service->end_handle,
2208 bt_uuid_to_uuid128(&uuid, &service->uuid);
2210 service->path = g_strdup_printf("%s/service%04x", device_path,
2211 service->start_handle);
2213 if (!g_dbus_register_interface(btd_get_dbus_connection(), service->path,
2215 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2216 NULL, service_signals,
2221 service, service_free)) {
2222 error("Unable to register GATT service with handle 0x%04x for "
2224 service->start_handle,
2226 service_free(service);
2231 DBG("Exported GATT service: %s", service->path);
2233 /* Set service active so we can skip discovering next time */
2234 gatt_db_service_set_active(attr, true);
2236 /* Mark the service as claimed since it going to be exported */
2237 gatt_db_service_set_claimed(attr, true);
2242 static void on_service_removed(void *data, void *user_data)
2244 struct service *service = data;
2245 struct service *removed_service = user_data;
2247 if (queue_remove(service->incl_services, removed_service))
2248 g_dbus_emit_property_changed(btd_get_dbus_connection(),
2254 static void unregister_service(void *data)
2256 struct service *service = data;
2257 struct btd_gatt_client *client = service->client;
2259 DBG("Removing GATT service: %s", service->path);
2261 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2262 if (service->idle_id)
2263 g_source_remove(service->idle_id);
2266 queue_remove_all(service->chrcs, NULL, NULL, unregister_characteristic);
2267 queue_remove_all(service->incl_services, NULL, NULL, NULL);
2269 queue_foreach(client->services, on_service_removed, service);
2271 g_dbus_unregister_interface(btd_get_dbus_connection(), service->path,
2272 GATT_SERVICE_IFACE);
2275 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2276 static void notify_service_added(struct service *service)
2280 if (service == NULL) {
2281 error("service is NULL");
2285 if (service->path == NULL) {
2286 error("service->path is NULL");
2289 if (!service->chrcs_ready) {
2290 error("service is not ready");
2294 svc_path = g_strdup(service->path);
2296 g_dbus_emit_signal(btd_get_dbus_connection(), service->path,
2297 GATT_SERVICE_IFACE, "GattServiceAdded",
2298 DBUS_TYPE_STRING, &svc_path,
2306 static void notify_chrcs(struct service *service)
2309 if (service->chrcs_ready ||
2310 !queue_isempty(service->pending_ext_props))
2313 service->chrcs_ready = true;
2315 g_dbus_emit_property_changed(btd_get_dbus_connection(), service->path,
2318 if (service->primary == true) {
2319 DBG("Notify Service Added");
2320 notify_service_added(service);
2325 struct export_data {
2330 static void export_desc(struct gatt_db_attribute *attr, void *user_data)
2332 struct descriptor *desc;
2333 struct export_data *data = user_data;
2334 struct characteristic *charac = data->root;
2339 desc = descriptor_create(attr, charac);
2341 data->failed = true;
2345 queue_push_tail(charac->descs, desc);
2348 static bool create_descriptors(struct gatt_db_attribute *attr,
2349 struct characteristic *charac)
2351 struct export_data data;
2354 data.failed = false;
2356 gatt_db_service_foreach_desc(attr, export_desc, &data);
2358 return !data.failed;
2361 static void export_char(struct gatt_db_attribute *attr, void *user_data)
2363 struct characteristic *charac;
2364 struct export_data *data = user_data;
2365 struct service *service = data->root;
2370 charac = characteristic_create(attr, service);
2374 if (!create_descriptors(attr, charac)) {
2375 unregister_characteristic(charac);
2379 queue_push_tail(service->chrcs, charac);
2381 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2382 if (charac->ext_props_handle)
2383 queue_push_tail(service->pending_ext_props, charac);
2389 data->failed = true;
2392 static bool create_characteristics(struct gatt_db_attribute *attr,
2393 struct service *service)
2395 struct export_data data;
2397 data.root = service;
2398 data.failed = false;
2400 gatt_db_service_foreach_char(attr, export_char, &data);
2402 return !data.failed;
2405 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2406 static gboolean set_chrcs_ready(gpointer user_data)
2408 struct service *service = user_data;
2410 service->idle_id = 0;
2411 notify_chrcs(service);
2416 static void export_service(struct gatt_db_attribute *attr, void *user_data)
2418 struct btd_gatt_client *client = user_data;
2419 struct service *service;
2421 if (gatt_db_service_get_claimed(attr))
2424 service = service_create(attr, client);
2428 if (!create_characteristics(attr, service)) {
2429 error("Exporting characteristics failed");
2430 unregister_service(service);
2434 queue_push_tail(client->services, service);
2436 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2438 * Asynchronously update the "Characteristics" property of the service.
2439 * If there are any pending reads to obtain the value of the "Extended
2440 * Properties" descriptor then wait until they are complete.
2442 if (!service->chrcs_ready && queue_isempty(service->pending_ext_props))
2443 service->idle_id = g_idle_add(set_chrcs_ready, service);
2447 static bool match_service_handle(const void *a, const void *b)
2449 const struct service *service = a;
2450 uint16_t start_handle = PTR_TO_UINT(b);
2452 return service->start_handle == start_handle;
2455 struct update_incl_data {
2456 struct service *service;
2460 static void update_included_service(struct gatt_db_attribute *attrib,
2463 struct update_incl_data *update_data = user_data;
2464 struct btd_gatt_client *client = update_data->service->client;
2465 struct service *service = update_data->service;
2466 struct service *incl_service;
2467 uint16_t start_handle;
2469 gatt_db_attribute_get_incl_data(attrib, NULL, &start_handle, NULL);
2471 incl_service = queue_find(client->services, match_service_handle,
2472 UINT_TO_PTR(start_handle));
2477 /* Check if service is already on list */
2478 if (queue_find(service->incl_services, NULL, incl_service))
2481 queue_push_tail(service->incl_services, incl_service);
2482 update_data->changed = true;
2485 static void update_included_services(void *data, void *user_data)
2487 struct btd_gatt_client *client = user_data;
2488 struct service *service = data;
2489 struct gatt_db_attribute *attr;
2490 struct update_incl_data inc_data = {
2495 attr = gatt_db_get_attribute(client->db, service->start_handle);
2496 gatt_db_service_foreach_incl(attr, update_included_service, &inc_data);
2498 if (inc_data.changed)
2499 g_dbus_emit_property_changed(btd_get_dbus_connection(),
2505 static void create_services(struct btd_gatt_client *client)
2507 DBG("Exporting objects for GATT services: %s", client->devaddr);
2509 gatt_db_foreach_service(client->db, NULL, export_service, client);
2511 queue_foreach(client->services, update_included_services, client);
2514 struct btd_gatt_client *btd_gatt_client_new(struct btd_device *device)
2516 struct btd_gatt_client *client;
2522 db = btd_device_get_gatt_db(device);
2526 client = new0(struct btd_gatt_client, 1);
2527 client->services = queue_new();
2528 client->all_notify_clients = queue_new();
2529 client->ios = queue_new();
2530 client->device = device;
2531 ba2str(device_get_address(device), client->devaddr);
2533 client->db = gatt_db_ref(db);
2538 void btd_gatt_client_destroy(struct btd_gatt_client *client)
2543 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2544 if (client->wait_charcs_id)
2545 g_source_remove(client->wait_charcs_id);
2547 queue_destroy(client->services, unregister_service);
2548 queue_destroy(client->all_notify_clients, NULL);
2549 queue_destroy(client->ios, NULL);
2550 bt_gatt_client_unref(client->gatt);
2551 gatt_db_unref(client->db);
2555 static void register_notify(void *data, void *user_data)
2557 struct notify_client *notify_client = data;
2558 struct btd_gatt_client *client = user_data;
2559 struct async_dbus_op *op;
2561 DBG("Re-register subscribed notification client");
2563 op = new0(struct async_dbus_op, 1);
2564 op->data = notify_client;
2566 notify_client->notify_id = bt_gatt_client_register_notify(client->gatt,
2567 notify_client->chrc->value_handle,
2568 register_notify_cb, notify_cb,
2569 op, async_dbus_op_free);
2570 if (notify_client->notify_id)
2573 async_dbus_op_free(op);
2575 DBG("Failed to re-register notification client");
2577 queue_remove(notify_client->chrc->notify_clients, notify_client);
2578 queue_remove(client->all_notify_clients, notify_client);
2580 notify_client_free(notify_client);
2583 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2584 static void check_chrcs_ready(void *data, void *user_data)
2586 gboolean *chrcs_ready = user_data;
2587 struct service *service = data;
2590 * Return FALSE if charcteristics are not ready or if there is
2591 * any pending request to read char. extended properties exist.
2593 if (!service->chrcs_ready ||
2594 !queue_isempty(service->pending_ext_props))
2595 *chrcs_ready = FALSE;
2598 static gboolean check_all_chrcs_ready(gpointer user_data)
2600 struct btd_gatt_client *client = user_data;
2601 gboolean all_chrcs_ready = TRUE;
2602 static int count = 0;
2604 queue_foreach(client->services, check_chrcs_ready, &all_chrcs_ready);
2607 * By adding below condition, forcing to call check_chrcs_ready()
2608 * function to check whether all char./extended properties are ready.
2609 * Above function would be called max. for 500 times (Assuming more
2610 * no of services). Emit signal only when all characteristics are ready.
2612 if (all_chrcs_ready == FALSE && count < 500) {
2618 * There are chances when all of the primary services are not found,
2619 * instead service changed is received while reading REQs in progress,
2620 * so emit signal after service changed operation is completed (if any).
2622 if (bt_gatt_client_svc_changed_received(client->gatt))
2625 device_set_gatt_connected(client->device, TRUE);
2627 client->wait_charcs_id = 0;
2635 void btd_gatt_client_ready(struct btd_gatt_client *client)
2640 if (!client->gatt) {
2641 struct bt_gatt_client *gatt;
2643 gatt = btd_device_get_gatt_client(client->device);
2644 client->gatt = bt_gatt_client_clone(gatt);
2645 if (!client->gatt) {
2646 error("GATT client not initialized");
2651 client->ready = true;
2653 DBG("GATT client ready");
2655 create_services(client);
2657 DBG("Features 0x%02x", client->features);
2659 if (!client->features) {
2660 client->features = bt_gatt_client_get_features(client->gatt);
2661 DBG("Update Features 0x%02x", client->features);
2662 if (client->features & BT_GATT_CHRC_CLI_FEAT_EATT)
2663 btd_gatt_client_eatt_connect(client);
2666 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2668 * In case of more number of services and services having
2669 * characteristics extended properties; GattConnected signal
2670 * should be emitted only after all the characteristics are ready.
2671 * This piece of code checks all the characteristics periodically and
2672 * emit the signal if characteristics are ready.
2674 if (client->wait_charcs_id > 0)
2675 g_source_remove(client->wait_charcs_id);
2677 client->wait_charcs_id = g_timeout_add(10,
2678 check_all_chrcs_ready, client);
2683 static void eatt_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
2685 struct btd_gatt_client *client = user_data;
2690 device_attach_att(client->device, io);
2693 void btd_gatt_client_eatt_connect(struct btd_gatt_client *client)
2695 struct bt_att *att = bt_gatt_client_get_att(client->gatt);
2696 struct btd_device *dev = client->device;
2697 struct btd_adapter *adapter = device_get_adapter(dev);
2699 GError *gerr = NULL;
2703 if (!(client->features & BT_GATT_CHRC_CLI_FEAT_EATT))
2705 if (bt_att_get_channels(att) == btd_opts.gatt_channels)
2708 ba2str(device_get_address(dev), addr);
2710 for (i = bt_att_get_channels(att); i < btd_opts.gatt_channels; i++) {
2711 int defer_timeout = i + 1 < btd_opts.gatt_channels ? 1 : 0;
2713 DBG("Connection attempt to: %s defer %s", addr,
2714 defer_timeout ? "true" : "false");
2716 /* Attempt to connect using the Ext-Flowctl */
2717 io = bt_io_connect(eatt_connect_cb, client, NULL, &gerr,
2718 BT_IO_OPT_SOURCE_BDADDR,
2719 btd_adapter_get_address(adapter),
2720 BT_IO_OPT_SOURCE_TYPE,
2721 btd_adapter_get_address_type(adapter),
2722 BT_IO_OPT_DEST_BDADDR,
2723 device_get_address(dev),
2724 BT_IO_OPT_DEST_TYPE,
2725 device_get_le_address_type(dev),
2726 BT_IO_OPT_MODE, BT_IO_MODE_EXT_FLOWCTL,
2727 BT_IO_OPT_PSM, BT_ATT_EATT_PSM,
2728 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
2729 BT_IO_OPT_MTU, btd_opts.gatt_mtu,
2730 BT_IO_OPT_DEFER_TIMEOUT, defer_timeout,
2735 /* Fallback to legacy LE Mode */
2736 io = bt_io_connect(eatt_connect_cb, client, NULL, &gerr,
2737 BT_IO_OPT_SOURCE_BDADDR,
2738 btd_adapter_get_address(adapter),
2739 BT_IO_OPT_SOURCE_TYPE,
2740 btd_adapter_get_address_type(adapter),
2741 BT_IO_OPT_DEST_BDADDR,
2742 device_get_address(dev),
2743 BT_IO_OPT_DEST_TYPE,
2744 device_get_le_address_type(dev),
2745 BT_IO_OPT_PSM, BT_ATT_EATT_PSM,
2746 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
2747 BT_IO_OPT_MTU, btd_opts.gatt_mtu,
2750 error("EATT bt_io_connect(%s): %s", addr,
2757 g_io_channel_unref(io);
2761 void btd_gatt_client_connected(struct btd_gatt_client *client)
2763 struct bt_gatt_client *gatt;
2765 gatt = btd_device_get_gatt_client(client->device);
2767 error("GATT client not initialized");
2771 DBG("Device connected.");
2773 bt_gatt_client_unref(client->gatt);
2774 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2775 /* The Client data is not getting updated
2776 * while clone logic is used, because of which
2777 * the notification callbacks and other debug callbacks
2778 * are not getting set properly, untill the clone logic
2779 * is fixed, the ref logic is used */
2780 client->gatt = bt_gatt_client_ref(gatt);
2782 client->gatt = bt_gatt_client_clone(gatt);
2785 * Services have already been created before. Re-enable notifications
2786 * for any pre-registered notification sessions.
2788 queue_foreach(client->all_notify_clients, register_notify, client);
2791 void btd_gatt_client_service_added(struct btd_gatt_client *client,
2792 struct gatt_db_attribute *attrib)
2794 if (!client || !attrib || !client->ready)
2797 export_service(attrib, client);
2799 queue_foreach(client->services, update_included_services, client);
2802 void btd_gatt_client_service_removed(struct btd_gatt_client *client,
2803 struct gatt_db_attribute *attrib)
2805 uint16_t start_handle, end_handle;
2807 if (!client || !attrib || !client->ready)
2810 gatt_db_attribute_get_service_handles(attrib, &start_handle,
2813 DBG("GATT Services Removed - start: 0x%04x, end: 0x%04x", start_handle,
2815 queue_remove_all(client->services, match_service_handle,
2816 UINT_TO_PTR(start_handle),
2817 unregister_service);
2820 static void clear_notify_id(void *data, void *user_data)
2822 struct notify_client *client = data;
2824 client->notify_id = 0;
2827 static void client_shutdown(void *data)
2832 void btd_gatt_client_disconnected(struct btd_gatt_client *client)
2834 if (!client || !client->gatt)
2837 DBG("Device disconnected. Cleaning up.");
2839 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2840 if (client->wait_charcs_id) {
2841 g_source_remove(client->wait_charcs_id);
2842 client->wait_charcs_id = 0;
2845 queue_remove_all(client->ios, NULL, NULL, client_shutdown);
2848 * TODO: Once GATT over BR/EDR is properly supported, we should pass the
2849 * correct bdaddr_type based on the transport over which GATT is being
2852 queue_foreach(client->all_notify_clients, clear_notify_id, NULL);
2854 bt_gatt_client_unref(client->gatt);
2855 client->gatt = NULL;
2858 struct foreach_service_data {
2859 btd_gatt_client_service_path_t func;
2863 static void client_service_foreach(void *data, void *user_data)
2865 struct service *service = data;
2866 struct foreach_service_data *foreach_data = user_data;
2868 foreach_data->func(service->path, foreach_data->user_data);
2871 void btd_gatt_client_foreach_service(struct btd_gatt_client *client,
2872 btd_gatt_client_service_path_t func,
2875 struct foreach_service_data data;
2881 data.user_data = user_data;
2883 queue_foreach(client->services, client_service_foreach, &data);