3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2015 Google Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
28 #include "lib/bluetooth.h"
30 #include "lib/sdp_lib.h"
32 #include "btio/btio.h"
33 #include "gdbus/gdbus.h"
34 #include "src/shared/util.h"
35 #include "src/shared/queue.h"
36 #include "src/shared/att.h"
37 #include "src/shared/gatt-db.h"
38 #include "src/shared/gatt-server.h"
43 #include "gatt-database.h"
44 #include "dbus-common.h"
56 #define GATT_MANAGER_IFACE "org.bluez.GattManager1"
57 #define GATT_SERVICE_IFACE "org.bluez.GattService1"
58 #define GATT_CHRC_IFACE "org.bluez.GattCharacteristic1"
59 #define GATT_DESC_IFACE "org.bluez.GattDescriptor1"
61 #define UUID_GAP 0x1800
62 #define UUID_GATT 0x1801
65 #define MIN(a, b) ((a) < (b) ? (a) : (b))
68 struct btd_gatt_database {
69 struct btd_adapter *adapter;
76 struct queue *device_states;
77 struct queue *ccc_callbacks;
78 struct gatt_db_attribute *svc_chngd;
79 struct gatt_db_attribute *svc_chngd_ccc;
81 struct queue *profiles;
85 struct btd_gatt_database *database;
91 struct queue *services;
94 struct external_service {
96 char *path; /* Path to GattService1 */
98 struct gatt_db_attribute *attrib;
104 struct external_profile {
105 struct btd_gatt_database *database;
107 char *path; /* Path to GattProfile1 */
109 struct queue *profiles; /* btd_profile list */
112 struct external_chrc {
113 struct external_service *service;
118 struct gatt_db_attribute *attrib;
119 struct gatt_db_attribute *ccc;
120 struct queue *pending_reads;
121 struct queue *pending_writes;
122 unsigned int ntfy_cnt;
125 struct external_desc {
126 struct external_service *service;
130 struct gatt_db_attribute *attrib;
132 struct queue *pending_reads;
133 struct queue *pending_writes;
138 struct gatt_db_attribute *attrib;
139 struct queue *owner_queue;
141 #ifdef __TIZEN_PATCH__
147 struct device_state {
150 struct queue *ccc_states;
160 btd_gatt_database_ccc_write_t callback;
161 btd_gatt_database_destroy_t destroy;
170 static void ccc_cb_free(void *data)
172 struct ccc_cb_data *ccc_cb = data;
175 ccc_cb->destroy(ccc_cb->user_data);
180 static bool ccc_cb_match_service(const void *data, const void *match_data)
182 const struct ccc_cb_data *ccc_cb = data;
183 const struct gatt_db_attribute *attrib = match_data;
186 if (!gatt_db_attribute_get_service_handles(attrib, &start, &end))
189 return ccc_cb->handle >= start && ccc_cb->handle <= end;
192 static bool ccc_cb_match_handle(const void *data, const void *match_data)
194 const struct ccc_cb_data *ccc_cb = data;
195 uint16_t handle = PTR_TO_UINT(match_data);
197 return ccc_cb->handle == handle;
200 static bool dev_state_match(const void *a, const void *b)
202 const struct device_state *dev_state = a;
203 const struct device_info *dev_info = b;
205 return bacmp(&dev_state->bdaddr, &dev_info->bdaddr) == 0 &&
206 dev_state->bdaddr_type == dev_info->bdaddr_type;
209 static struct device_state *
210 find_device_state(struct btd_gatt_database *database, bdaddr_t *bdaddr,
213 struct device_info dev_info;
215 memset(&dev_info, 0, sizeof(dev_info));
217 bacpy(&dev_info.bdaddr, bdaddr);
218 dev_info.bdaddr_type = bdaddr_type;
220 return queue_find(database->device_states, dev_state_match, &dev_info);
223 #ifdef __TIZEN_PATCH__
224 static bool dev_addr_match(const void *a, const void *b)
226 const struct device_state *dev_state = a;
227 const struct device_info *dev_info = b;
229 if (bacmp(&dev_state->bdaddr, &dev_info->bdaddr) == 0)
235 static struct device_state *
236 find_device_state_from_address(struct btd_gatt_database *database, const bdaddr_t *bdaddr)
238 struct device_info dev_info;
240 memset(&dev_info, 0, sizeof(dev_info));
242 bacpy(&dev_info.bdaddr, bdaddr);
244 return queue_find(database->device_states, dev_addr_match, &dev_info);
248 static bool ccc_state_match(const void *a, const void *b)
250 const struct ccc_state *ccc = a;
251 uint16_t handle = PTR_TO_UINT(b);
253 return ccc->handle == handle;
256 static struct ccc_state *find_ccc_state(struct device_state *dev_state,
259 return queue_find(dev_state->ccc_states, ccc_state_match,
260 UINT_TO_PTR(handle));
263 static struct device_state *device_state_create(bdaddr_t *bdaddr,
266 struct device_state *dev_state;
268 dev_state = new0(struct device_state, 1);
269 dev_state->ccc_states = queue_new();
270 bacpy(&dev_state->bdaddr, bdaddr);
271 dev_state->bdaddr_type = bdaddr_type;
276 static struct device_state *get_device_state(struct btd_gatt_database *database,
280 struct device_state *dev_state;
283 * Find and return a device state. If a matching state doesn't exist,
284 * then create a new one.
286 dev_state = find_device_state(database, bdaddr, bdaddr_type);
290 dev_state = device_state_create(bdaddr, bdaddr_type);
292 queue_push_tail(database->device_states, dev_state);
297 static struct ccc_state *get_ccc_state(struct btd_gatt_database *database,
302 struct device_state *dev_state;
303 struct ccc_state *ccc;
305 dev_state = get_device_state(database, bdaddr, bdaddr_type);
307 ccc = find_ccc_state(dev_state, handle);
311 ccc = new0(struct ccc_state, 1);
312 ccc->handle = handle;
313 queue_push_tail(dev_state->ccc_states, ccc);
318 static void device_state_free(void *data)
320 struct device_state *state = data;
322 queue_destroy(state->ccc_states, free);
326 static void cancel_pending_read(void *data)
328 struct pending_op *op = data;
330 gatt_db_attribute_read_result(op->attrib, op->id,
331 BT_ATT_ERROR_REQUEST_NOT_SUPPORTED,
333 op->owner_queue = NULL;
336 static void cancel_pending_write(void *data)
338 struct pending_op *op = data;
340 gatt_db_attribute_write_result(op->attrib, op->id,
341 BT_ATT_ERROR_REQUEST_NOT_SUPPORTED);
342 op->owner_queue = NULL;
345 static void chrc_free(void *data)
347 struct external_chrc *chrc = data;
349 queue_destroy(chrc->pending_reads, cancel_pending_read);
350 queue_destroy(chrc->pending_writes, cancel_pending_write);
354 g_dbus_proxy_set_property_watch(chrc->proxy, NULL, NULL);
355 g_dbus_proxy_unref(chrc->proxy);
360 static void desc_free(void *data)
362 struct external_desc *desc = data;
364 queue_destroy(desc->pending_reads, cancel_pending_read);
365 queue_destroy(desc->pending_writes, cancel_pending_write);
367 g_dbus_proxy_unref(desc->proxy);
368 g_free(desc->chrc_path);
373 static void service_free(void *data)
375 struct external_service *service = data;
377 queue_destroy(service->chrcs, chrc_free);
378 queue_destroy(service->descs, desc_free);
381 gatt_db_remove_service(service->app->database->db,
384 if (service->app->client)
385 g_dbus_proxy_unref(service->proxy);
387 g_free(service->path);
392 static void app_free(void *data)
394 struct gatt_app *app = data;
396 queue_destroy(app->services, service_free);
399 g_dbus_client_set_disconnect_watch(app->client, NULL, NULL);
400 g_dbus_client_set_proxy_handlers(app->client, NULL, NULL,
402 g_dbus_client_set_ready_watch(app->client, NULL, NULL);
403 g_dbus_client_unref(app->client);
407 dbus_message_unref(app->reg);
415 static void profile_remove(void *data)
417 struct btd_profile *p = data;
419 DBG("Removed \"%s\"", p->name);
421 adapter_foreach(adapter_remove_profile, p);
422 btd_profile_unregister(p);
424 g_free((void *) p->name);
425 g_free((void *) p->remote_uuid);
430 static void profile_release(struct external_profile *profile)
437 DBG("Releasing \"%s\"", profile->owner);
439 g_dbus_remove_watch(btd_get_dbus_connection(), profile->id);
441 msg = dbus_message_new_method_call(profile->owner, profile->path,
442 "org.bluez.GattProfile1",
445 g_dbus_send_message(btd_get_dbus_connection(), msg);
448 static void profile_free(void *data)
450 struct external_profile *profile = data;
452 queue_destroy(profile->profiles, profile_remove);
454 profile_release(profile);
456 g_free(profile->owner);
457 g_free(profile->path);
462 static void gatt_database_free(void *data)
464 struct btd_gatt_database *database = data;
466 if (database->le_io) {
467 g_io_channel_shutdown(database->le_io, FALSE, NULL);
468 g_io_channel_unref(database->le_io);
471 if (database->l2cap_io) {
472 g_io_channel_shutdown(database->l2cap_io, FALSE, NULL);
473 g_io_channel_unref(database->l2cap_io);
476 if (database->gatt_handle)
477 adapter_service_remove(database->adapter,
478 database->gatt_handle);
480 if (database->gap_handle)
481 adapter_service_remove(database->adapter, database->gap_handle);
483 /* TODO: Persistently store CCC states before freeing them */
484 gatt_db_unregister(database->db, database->db_id);
486 queue_destroy(database->device_states, device_state_free);
487 queue_destroy(database->apps, app_free);
488 queue_destroy(database->profiles, profile_free);
489 queue_destroy(database->ccc_callbacks, ccc_cb_free);
490 database->device_states = NULL;
491 database->ccc_callbacks = NULL;
493 gatt_db_unref(database->db);
495 btd_adapter_unref(database->adapter);
499 static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
501 struct btd_adapter *adapter;
502 struct btd_device *device;
506 DBG("New incoming LE ATT connection");
509 error("%s", gerr->message);
513 bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src,
514 BT_IO_OPT_DEST_BDADDR, &dst,
515 BT_IO_OPT_DEST_TYPE, &dst_type,
518 error("bt_io_get: %s", gerr->message);
523 adapter = adapter_find(&src);
527 device = btd_adapter_get_device(adapter, &dst, dst_type);
531 device_attach_att(device, io);
534 #ifdef __TIZEN_PATCH__
535 #define LE_BEARER_POSTFIX " LE"
536 #define LE_BEARER_POSTFIX_LEN 3
538 static bool get_dst_info(struct bt_att *att, bdaddr_t *dst, uint8_t *dst_type);
541 static void gap_device_name_read_cb(struct gatt_db_attribute *attrib,
542 unsigned int id, uint16_t offset,
543 uint8_t opcode, struct bt_att *att,
546 struct btd_gatt_database *database = user_data;
549 const uint8_t *value = NULL;
550 const char *device_name;
551 #ifdef __TIZEN_PATCH__
552 bdaddr_t dst = { { 0 } };
553 uint8_t dst_type = 0;
554 char le_name[MAX_NAME_LENGTH + 1];
557 DBG("GAP Device Name read request\n");
559 device_name = btd_adapter_get_name(database->adapter);
560 #ifdef __TIZEN_PATCH__
561 if (get_dst_info(att, &dst, &dst_type) && dst_type != BDADDR_BREDR) {
564 g_strlcpy(le_name, device_name,
565 sizeof(le_name) - LE_BEARER_POSTFIX_LEN);
566 if (!g_utf8_validate(le_name, -1, (const char **)&ptr))
569 g_strlcat(le_name, LE_BEARER_POSTFIX, sizeof(le_name));
570 DBG("Append LE bearer postfix : %s", le_name);
572 device_name = le_name;
575 len = strlen(device_name);
578 error = BT_ATT_ERROR_INVALID_OFFSET;
583 value = len ? (const uint8_t *) &device_name[offset] : NULL;
586 gatt_db_attribute_read_result(attrib, id, error, value, len);
589 static void gap_appearance_read_cb(struct gatt_db_attribute *attrib,
590 unsigned int id, uint16_t offset,
591 uint8_t opcode, struct bt_att *att,
594 struct btd_gatt_database *database = user_data;
597 const uint8_t *value = NULL;
598 uint8_t appearance[2];
601 DBG("GAP Appearance read request\n");
603 dev_class = btd_adapter_get_class(database->adapter);
606 error = BT_ATT_ERROR_INVALID_OFFSET;
610 appearance[0] = dev_class & 0x00ff;
611 appearance[1] = (dev_class >> 8) & 0x001f;
614 value = len ? &appearance[offset] : NULL;
617 gatt_db_attribute_read_result(attrib, id, error, value, len);
620 #ifdef __TIZEN_PATCH__
621 static void gap_rpa_res_support_read_cb(struct gatt_db_attribute *attrib,
622 unsigned int id, uint16_t offset,
623 uint8_t opcode, struct bt_att *att,
626 struct btd_gatt_database *database = user_data;
629 const uint8_t *value = NULL;
630 uint8_t rpa_res_support = 0x00;
632 rpa_res_support = btd_adapter_get_rpa_res_support_value(database->adapter);
635 error = BT_ATT_ERROR_INVALID_OFFSET;
640 value = len ? &rpa_res_support : NULL;
643 gatt_db_attribute_read_result(attrib, id, error, value, len);
647 static sdp_record_t *record_new(uuid_t *uuid, uint16_t start, uint16_t end)
649 sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
650 uuid_t root_uuid, proto_uuid, l2cap;
651 sdp_record_t *record;
652 sdp_data_t *psm, *sh, *eh;
653 uint16_t lp = ATT_PSM;
661 record = sdp_record_alloc();
665 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
666 root = sdp_list_append(NULL, &root_uuid);
667 sdp_set_browse_groups(record, root);
668 sdp_list_free(root, NULL);
670 svclass_id = sdp_list_append(NULL, uuid);
671 sdp_set_service_classes(record, svclass_id);
672 sdp_list_free(svclass_id, NULL);
674 sdp_uuid16_create(&l2cap, L2CAP_UUID);
675 proto[0] = sdp_list_append(NULL, &l2cap);
676 psm = sdp_data_alloc(SDP_UINT16, &lp);
677 proto[0] = sdp_list_append(proto[0], psm);
678 apseq = sdp_list_append(NULL, proto[0]);
680 sdp_uuid16_create(&proto_uuid, ATT_UUID);
681 proto[1] = sdp_list_append(NULL, &proto_uuid);
682 sh = sdp_data_alloc(SDP_UINT16, &start);
683 proto[1] = sdp_list_append(proto[1], sh);
684 eh = sdp_data_alloc(SDP_UINT16, &end);
685 proto[1] = sdp_list_append(proto[1], eh);
686 apseq = sdp_list_append(apseq, proto[1]);
688 aproto = sdp_list_append(NULL, apseq);
689 sdp_set_access_protos(record, aproto);
694 sdp_list_free(proto[0], NULL);
695 sdp_list_free(proto[1], NULL);
696 sdp_list_free(apseq, NULL);
697 sdp_list_free(aproto, NULL);
702 static uint32_t database_add_record(struct btd_gatt_database *database,
704 struct gatt_db_attribute *attr,
707 sdp_record_t *record;
709 uuid_t svc, gap_uuid;
711 sdp_uuid16_create(&svc, uuid);
712 gatt_db_attribute_get_service_handles(attr, &start, &end);
714 record = record_new(&svc, start, end);
719 sdp_set_info_attr(record, name, "BlueZ", NULL);
721 sdp_uuid16_create(&gap_uuid, UUID_GAP);
722 if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) {
723 sdp_set_url_attr(record, "http://www.bluez.org/",
724 "http://www.bluez.org/",
725 "http://www.bluez.org/");
728 if (adapter_service_add(database->adapter, record) == 0)
729 return record->handle;
731 sdp_record_free(record);
735 static void populate_gap_service(struct btd_gatt_database *database)
738 struct gatt_db_attribute *service;
740 /* Add the GAP service */
741 bt_uuid16_create(&uuid, UUID_GAP);
743 #ifndef __TIZEN_PATCH__
744 service = gatt_db_add_service(database->db, &uuid, true, 5);
746 service = gatt_db_add_service(database->db, &uuid, true, 7);
749 database->gap_handle = database_add_record(database, UUID_GAP, service,
750 "Generic Access Profile");
753 * Device Name characteristic.
755 bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
756 gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
757 BT_GATT_CHRC_PROP_READ,
758 gap_device_name_read_cb,
762 * Device Appearance characteristic.
764 bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
765 gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
766 BT_GATT_CHRC_PROP_READ,
767 gap_appearance_read_cb,
770 #ifdef __TIZEN_PATCH__
771 /* Central address resolution characteristic */
772 bt_uuid16_create(&uuid, GATT_CHARAC_CENTRAL_RPA_RESOLUTION);
773 gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
774 BT_GATT_CHRC_PROP_READ,
775 gap_rpa_res_support_read_cb,
779 gatt_db_service_set_active(service, true);
782 static bool get_dst_info(struct bt_att *att, bdaddr_t *dst, uint8_t *dst_type)
784 GIOChannel *io = NULL;
787 io = g_io_channel_unix_new(bt_att_get_fd(att));
791 bt_io_get(io, &gerr, BT_IO_OPT_DEST_BDADDR, dst,
792 BT_IO_OPT_DEST_TYPE, dst_type,
795 error("gatt: bt_io_get: %s", gerr->message);
797 g_io_channel_unref(io);
801 g_io_channel_unref(io);
805 static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
806 unsigned int id, uint16_t offset,
807 uint8_t opcode, struct bt_att *att,
810 struct btd_gatt_database *database = user_data;
811 struct ccc_state *ccc;
814 const uint8_t *value = NULL;
819 handle = gatt_db_attribute_get_handle(attrib);
821 DBG("CCC read called for handle: 0x%04x", handle);
824 ecode = BT_ATT_ERROR_INVALID_OFFSET;
828 if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
829 ecode = BT_ATT_ERROR_UNLIKELY;
833 ccc = get_ccc_state(database, &bdaddr, bdaddr_type, handle);
836 value = len ? &ccc->value[offset] : NULL;
839 gatt_db_attribute_read_result(attrib, id, ecode, value, len);
842 static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib,
843 unsigned int id, uint16_t offset,
844 const uint8_t *value, size_t len,
845 uint8_t opcode, struct bt_att *att,
848 struct btd_gatt_database *database = user_data;
849 struct ccc_state *ccc;
850 struct ccc_cb_data *ccc_cb;
856 handle = gatt_db_attribute_get_handle(attrib);
858 DBG("CCC write called for handle: 0x%04x", handle);
860 if (!value || len != 2) {
861 ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
866 ecode = BT_ATT_ERROR_INVALID_OFFSET;
870 if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
871 ecode = BT_ATT_ERROR_UNLIKELY;
875 ccc = get_ccc_state(database, &bdaddr, bdaddr_type, handle);
877 ccc_cb = queue_find(database->ccc_callbacks, ccc_cb_match_handle,
878 UINT_TO_PTR(gatt_db_attribute_get_handle(attrib)));
880 ecode = BT_ATT_ERROR_UNLIKELY;
884 /* If value is identical, then just succeed */
885 if (ccc->value[0] == value[0] && ccc->value[1] == value[1])
888 if (ccc_cb->callback)
889 ecode = ccc_cb->callback(get_le16(value), ccc_cb->user_data);
892 ccc->value[0] = value[0];
893 ccc->value[1] = value[1];
897 gatt_db_attribute_write_result(attrib, id, ecode);
900 static struct gatt_db_attribute *
901 service_add_ccc(struct gatt_db_attribute *service,
902 struct btd_gatt_database *database,
903 btd_gatt_database_ccc_write_t write_callback,
905 btd_gatt_database_destroy_t destroy)
907 struct gatt_db_attribute *ccc;
908 struct ccc_cb_data *ccc_cb;
911 ccc_cb = new0(struct ccc_cb_data, 1);
913 bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
914 ccc = gatt_db_service_add_descriptor(service, &uuid,
915 BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
916 gatt_ccc_read_cb, gatt_ccc_write_cb, database);
918 error("Failed to create CCC entry in database");
923 ccc_cb->handle = gatt_db_attribute_get_handle(ccc);
924 ccc_cb->callback = write_callback;
925 ccc_cb->destroy = destroy;
926 ccc_cb->user_data = user_data;
928 queue_push_tail(database->ccc_callbacks, ccc_cb);
933 struct gatt_db_attribute *
934 btd_gatt_database_add_ccc(struct btd_gatt_database *database,
935 uint16_t service_handle,
936 btd_gatt_database_ccc_write_t write_callback,
938 btd_gatt_database_destroy_t destroy)
940 struct gatt_db_attribute *service;
942 if (!database || !service_handle)
945 service = gatt_db_get_attribute(database->db, service_handle);
947 error("No service exists with handle: 0x%04x", service_handle);
951 return service_add_ccc(service, database, write_callback, user_data,
955 static void populate_gatt_service(struct btd_gatt_database *database)
958 struct gatt_db_attribute *service;
960 /* Add the GATT service */
961 bt_uuid16_create(&uuid, UUID_GATT);
962 service = gatt_db_add_service(database->db, &uuid, true, 4);
963 database->gatt_handle = database_add_record(database, UUID_GATT,
965 "Generic Attribute Profile");
967 bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
968 database->svc_chngd = gatt_db_service_add_characteristic(service, &uuid,
969 BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_INDICATE,
970 NULL, NULL, database);
972 database->svc_chngd_ccc = service_add_ccc(service, database, NULL, NULL,
975 gatt_db_service_set_active(service, true);
978 static void register_core_services(struct btd_gatt_database *database)
980 populate_gap_service(database);
981 populate_gatt_service(database);
985 struct btd_gatt_database *database;
986 uint16_t handle, ccc_handle;
987 const uint8_t *value;
992 #ifdef __TIZEN_PATCH__
993 struct notify_indicate {
994 struct btd_gatt_database *database;
996 uint16_t handle, ccc_handle;
997 const uint8_t *value;
1002 struct notify_indicate_cb {
1004 struct btd_device *device;
1007 static void indicate_confirm_free(void *data)
1009 struct notify_indicate_cb *indicate = data;
1015 static void indicate_confirm_setup_cb(DBusMessageIter *iter, void *user_data)
1017 struct btd_device *device = user_data;
1018 char dstaddr[18] = { 0 };
1019 char *addr_value = NULL;
1020 gboolean complete = FALSE;
1022 ba2str(device_get_address(device), dstaddr);
1023 addr_value = g_strdup(dstaddr);
1025 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
1029 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN,
1033 static void indicate_confirm_reply_cb(DBusMessage *message, void *user_data)
1037 dbus_error_init(&error);
1039 if (dbus_set_error_from_message(&error, message) == TRUE) {
1040 DBG("Failed to send indication/notification");
1041 dbus_error_free(&error);
1047 static void conf_cb(void *user_data)
1049 DBG("GATT server received confirmation");
1050 #ifdef __TIZEN_PATCH__
1051 struct notify_indicate_cb *confirm = user_data;
1054 /* Send confirmation to application */
1055 if (g_dbus_proxy_method_call(confirm->proxy, "IndicateConfirm",
1056 indicate_confirm_setup_cb,
1057 indicate_confirm_reply_cb, confirm->device,
1064 #ifdef __TIZEN_PATCH__
1065 static void send_notification_indication_to_device(void *data, void *user_data)
1067 struct device_state *device_state = data;
1068 struct notify_indicate *notify_indicate = user_data;
1069 struct ccc_state *ccc;
1070 struct btd_device *device;
1071 struct notify_indicate_cb *confirm;
1073 ccc = find_ccc_state(device_state, notify_indicate->ccc_handle);
1077 if (!ccc->value[0] || (notify_indicate->indicate && !(ccc->value[0] & 0x02)))
1080 device = btd_adapter_get_device(notify_indicate->database->adapter,
1081 &device_state->bdaddr,
1082 device_state->bdaddr_type);
1086 confirm = new0(struct notify_indicate_cb, 1);
1087 confirm->proxy = notify_indicate->proxy;
1088 confirm->device = device;
1090 * TODO: If the device is not connected but bonded, send the
1091 * notification/indication when it becomes connected.
1093 if (!notify_indicate->indicate) {
1094 DBG("GATT server sending notification");
1095 bt_gatt_server_send_notification(
1096 btd_device_get_gatt_server(device),
1097 notify_indicate->handle, notify_indicate->value,
1098 notify_indicate->len);
1099 /* In case of Notification, send response to application
1100 * as remote device do not respond for notification */
1105 DBG("GATT server sending indication");
1107 bt_gatt_server_send_indication(btd_device_get_gatt_server(device),
1108 notify_indicate->handle,
1109 notify_indicate->value,
1110 notify_indicate->len, conf_cb,
1111 confirm, indicate_confirm_free);
1114 static void send_notification_indication_to_devices(GDBusProxy *proxy,
1115 struct btd_gatt_database *database,
1116 uint16_t handle, const uint8_t *value,
1117 uint16_t len, uint16_t ccc_handle,
1120 struct notify_indicate notify_indicate;
1122 memset(¬ify_indicate, 0, sizeof(notify_indicate));
1124 notify_indicate.database = database;
1125 notify_indicate.proxy = proxy;
1126 notify_indicate.handle = handle;
1127 notify_indicate.ccc_handle = ccc_handle;
1128 notify_indicate.value = value;
1129 notify_indicate.len = len;
1130 notify_indicate.indicate = indicate;
1132 queue_foreach(database->device_states, send_notification_indication_to_device,
1136 static void send_unicast_notification_indication_to_device(GDBusProxy *proxy,
1137 struct btd_gatt_database *database,
1138 uint16_t handle, const uint8_t *value,
1139 uint16_t len, uint16_t ccc_handle,
1140 bool indicate, const bdaddr_t *unicast_addr)
1142 struct device_state *dev_state;
1143 struct notify_indicate notify_indicate;
1146 memset(¬ify_indicate, 0, sizeof(notify_indicate));
1148 notify_indicate.database = database;
1149 notify_indicate.proxy = proxy;
1150 notify_indicate.handle = handle;
1151 notify_indicate.ccc_handle = ccc_handle;
1152 notify_indicate.value = value;
1153 notify_indicate.len = len;
1154 notify_indicate.indicate = indicate;
1156 /* Find and return a device state. */
1157 dev_state = find_device_state_from_address(database, unicast_addr);
1160 send_notification_indication_to_device(dev_state, ¬ify_indicate);
1164 static void send_notification_to_device(void *data, void *user_data)
1166 struct device_state *device_state = data;
1167 struct notify *notify = user_data;
1168 struct ccc_state *ccc;
1169 struct btd_device *device;
1171 ccc = find_ccc_state(device_state, notify->ccc_handle);
1175 if (!ccc->value[0] || (notify->indicate && !(ccc->value[0] & 0x02)))
1178 device = btd_adapter_get_device(notify->database->adapter,
1179 &device_state->bdaddr,
1180 device_state->bdaddr_type);
1185 * TODO: If the device is not connected but bonded, send the
1186 * notification/indication when it becomes connected.
1188 if (!notify->indicate) {
1189 DBG("GATT server sending notification");
1190 bt_gatt_server_send_notification(
1191 btd_device_get_gatt_server(device),
1192 notify->handle, notify->value,
1197 DBG("GATT server sending indication");
1198 bt_gatt_server_send_indication(btd_device_get_gatt_server(device),
1201 notify->len, conf_cb,
1205 static void send_notification_to_devices(struct btd_gatt_database *database,
1206 uint16_t handle, const uint8_t *value,
1207 uint16_t len, uint16_t ccc_handle,
1210 struct notify notify;
1212 memset(¬ify, 0, sizeof(notify));
1214 notify.database = database;
1215 notify.handle = handle;
1216 notify.ccc_handle = ccc_handle;
1217 notify.value = value;
1219 notify.indicate = indicate;
1221 queue_foreach(database->device_states, send_notification_to_device,
1225 static void send_service_changed(struct btd_gatt_database *database,
1226 struct gatt_db_attribute *attrib)
1228 uint16_t start, end;
1230 uint16_t handle, ccc_handle;
1232 if (!gatt_db_attribute_get_service_handles(attrib, &start, &end)) {
1233 error("Failed to obtain changed service handles");
1237 handle = gatt_db_attribute_get_handle(database->svc_chngd);
1238 ccc_handle = gatt_db_attribute_get_handle(database->svc_chngd_ccc);
1240 if (!handle || !ccc_handle) {
1241 error("Failed to obtain handles for \"Service Changed\""
1246 put_le16(start, value);
1247 put_le16(end, value + 2);
1249 send_notification_to_devices(database, handle, value, sizeof(value),
1253 static void gatt_db_service_added(struct gatt_db_attribute *attrib,
1256 struct btd_gatt_database *database = user_data;
1258 DBG("GATT Service added to local database");
1260 send_service_changed(database, attrib);
1263 static bool ccc_match_service(const void *data, const void *match_data)
1265 const struct ccc_state *ccc = data;
1266 const struct gatt_db_attribute *attrib = match_data;
1267 uint16_t start, end;
1269 if (!gatt_db_attribute_get_service_handles(attrib, &start, &end))
1272 return ccc->handle >= start && ccc->handle <= end;
1275 static void remove_device_ccc(void *data, void *user_data)
1277 struct device_state *state = data;
1279 queue_remove_all(state->ccc_states, ccc_match_service, user_data, free);
1282 static void gatt_db_service_removed(struct gatt_db_attribute *attrib,
1285 struct btd_gatt_database *database = user_data;
1287 DBG("Local GATT service removed");
1289 send_service_changed(database, attrib);
1291 queue_foreach(database->device_states, remove_device_ccc, attrib);
1292 queue_remove_all(database->ccc_callbacks, ccc_cb_match_service, attrib,
1296 struct svc_match_data {
1301 static bool match_app(const void *a, const void *b)
1303 const struct gatt_app *app = a;
1304 const struct svc_match_data *data = b;
1306 return g_strcmp0(app->path, data->path) == 0 &&
1307 g_strcmp0(app->owner, data->sender) == 0;
1310 static gboolean app_free_idle_cb(void *data)
1317 static void client_disconnect_cb(DBusConnection *conn, void *user_data)
1319 struct gatt_app *app = user_data;
1320 struct btd_gatt_database *database = app->database;
1322 DBG("Client disconnected");
1324 if (queue_remove(database->apps, app))
1328 static void remove_app(void *data)
1330 struct gatt_app *app = data;
1333 * Set callback to NULL to avoid potential race condition
1334 * when calling remove_app and GDBusClient unref.
1336 g_dbus_client_set_disconnect_watch(app->client, NULL, NULL);
1339 * Set proxy handlers to NULL, so that this gets called only once when
1340 * the first proxy that belongs to this service gets removed.
1342 g_dbus_client_set_proxy_handlers(app->client, NULL, NULL, NULL, NULL);
1345 queue_remove(app->database->apps, app);
1348 * Do not run in the same loop, this may be a disconnect
1349 * watch call and GDBusClient should not be destroyed.
1351 g_idle_add(app_free_idle_cb, app);
1354 static bool match_service_by_path(const void *a, const void *b)
1356 const struct external_service *service = a;
1357 const char *path = b;
1359 return strcmp(service->path, path) == 0;
1362 static bool parse_path(GDBusProxy *proxy, const char *name, const char **path)
1364 DBusMessageIter iter;
1366 if (!g_dbus_proxy_get_property(proxy, name, &iter))
1369 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
1372 dbus_message_iter_get_basic(&iter, path);
1377 static bool incr_attr_count(struct external_service *service, uint16_t incr)
1379 if (service->attr_cnt > UINT16_MAX - incr)
1382 service->attr_cnt += incr;
1387 static bool parse_chrc_flags(DBusMessageIter *array, uint8_t *props,
1392 *props = *ext_props = 0;
1395 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_STRING)
1398 dbus_message_iter_get_basic(array, &flag);
1400 if (!strcmp("broadcast", flag))
1401 *props |= BT_GATT_CHRC_PROP_BROADCAST;
1402 else if (!strcmp("read", flag))
1403 *props |= BT_GATT_CHRC_PROP_READ;
1404 else if (!strcmp("write-without-response", flag))
1405 *props |= BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP;
1406 else if (!strcmp("write", flag))
1407 *props |= BT_GATT_CHRC_PROP_WRITE;
1408 else if (!strcmp("notify", flag))
1409 *props |= BT_GATT_CHRC_PROP_NOTIFY;
1410 else if (!strcmp("indicate", flag))
1411 *props |= BT_GATT_CHRC_PROP_INDICATE;
1412 else if (!strcmp("authenticated-signed-writes", flag))
1413 *props |= BT_GATT_CHRC_PROP_AUTH;
1414 else if (!strcmp("reliable-write", flag))
1415 *ext_props |= BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE;
1416 else if (!strcmp("writable-auxiliaries", flag))
1417 *ext_props |= BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX;
1418 else if (!strcmp("encrypt-read", flag)) {
1419 *props |= BT_GATT_CHRC_PROP_READ;
1420 *ext_props |= BT_GATT_CHRC_EXT_PROP_ENC_READ;
1421 } else if (!strcmp("encrypt-write", flag)) {
1422 *props |= BT_GATT_CHRC_PROP_WRITE;
1423 *ext_props |= BT_GATT_CHRC_EXT_PROP_ENC_WRITE;
1424 } else if (!strcmp("encrypt-authenticated-read", flag)) {
1425 *props |= BT_GATT_CHRC_PROP_READ;
1426 *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_READ;
1427 } else if (!strcmp("encrypt-authenticated-write", flag)) {
1428 *props |= BT_GATT_CHRC_PROP_WRITE;
1429 *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_WRITE;
1431 error("Invalid characteristic flag: %s", flag);
1434 } while (dbus_message_iter_next(array));
1437 *props |= BT_GATT_CHRC_PROP_EXT_PROP;
1442 static bool parse_desc_flags(DBusMessageIter *array, uint32_t *perm)
1449 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_STRING)
1452 dbus_message_iter_get_basic(array, &flag);
1454 if (!strcmp("read", flag))
1455 *perm |= BT_ATT_PERM_READ;
1456 else if (!strcmp("write", flag))
1457 *perm |= BT_ATT_PERM_WRITE;
1458 else if (!strcmp("encrypt-read", flag))
1459 *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_ENCRYPT;
1460 else if (!strcmp("encrypt-write", flag))
1461 *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_ENCRYPT;
1462 else if (!strcmp("encrypt-authenticated-read", flag))
1463 *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN;
1464 else if (!strcmp("encrypt-authenticated-write", flag))
1465 *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN;
1467 error("Invalid descriptor flag: %s", flag);
1470 } while (dbus_message_iter_next(array));
1475 static bool parse_flags(GDBusProxy *proxy, uint8_t *props, uint8_t *ext_props,
1478 DBusMessageIter iter, array;
1480 if (!g_dbus_proxy_get_property(proxy, "Flags", &iter))
1483 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1486 dbus_message_iter_recurse(&iter, &array);
1489 return parse_desc_flags(&array, perm);
1491 return parse_chrc_flags(&array, props, ext_props);
1494 static struct external_chrc *chrc_create(struct gatt_app *app,
1498 struct external_service *service;
1499 struct external_chrc *chrc;
1500 const char *service_path;
1502 if (!parse_path(proxy, "Service", &service_path)) {
1503 error("Failed to obtain service path for characteristic");
1507 service = queue_find(app->services, match_service_by_path,
1510 error("Unable to find service for characteristic: %s", path);
1514 chrc = new0(struct external_chrc, 1);
1515 chrc->pending_reads = queue_new();
1516 chrc->pending_writes = queue_new();
1518 chrc->path = g_strdup(path);
1522 chrc->service = service;
1523 chrc->proxy = g_dbus_proxy_ref(proxy);
1526 * Add 2 for the characteristic declaration and the value
1529 if (!incr_attr_count(chrc->service, 2)) {
1530 error("Failed to increment attribute count");
1535 * Parse characteristic flags (i.e. properties) here since they
1536 * are used to determine if any special descriptors should be
1539 if (!parse_flags(proxy, &chrc->props, &chrc->ext_props, NULL)) {
1540 error("Failed to parse characteristic properties");
1544 if ((chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
1545 chrc->props & BT_GATT_CHRC_PROP_INDICATE) &&
1546 !incr_attr_count(chrc->service, 1)) {
1547 error("Failed to increment attribute count for CCC");
1551 if (chrc->ext_props && !incr_attr_count(chrc->service, 1)) {
1552 error("Failed to increment attribute count for CEP");
1556 queue_push_tail(chrc->service->chrcs, chrc);
1565 static bool match_chrc(const void *a, const void *b)
1567 const struct external_chrc *chrc = a;
1568 const char *path = b;
1570 return strcmp(chrc->path, path) == 0;
1573 static bool match_service_by_chrc(const void *a, const void *b)
1575 const struct external_service *service = a;
1576 const char *path = b;
1578 return queue_find(service->chrcs, match_chrc, path);
1581 static struct external_desc *desc_create(struct gatt_app *app,
1584 struct external_service *service;
1585 struct external_desc *desc;
1586 const char *chrc_path;
1588 if (!parse_path(proxy, "Characteristic", &chrc_path)) {
1589 error("Failed to obtain characteristic path for descriptor");
1593 service = queue_find(app->services, match_service_by_chrc, chrc_path);
1595 error("Unable to find service for characteristic: %s",
1600 desc = new0(struct external_desc, 1);
1601 desc->pending_reads = queue_new();
1602 desc->pending_writes = queue_new();
1604 desc->chrc_path = g_strdup(chrc_path);
1605 if (!desc->chrc_path)
1608 desc->service = service;
1609 desc->proxy = g_dbus_proxy_ref(proxy);
1611 /* Add 1 for the descriptor attribute */
1612 if (!incr_attr_count(desc->service, 1)) {
1613 error("Failed to increment attribute count");
1618 * Parse descriptors flags here since they are used to
1619 * determine the permission the descriptor should have
1621 if (!parse_flags(proxy, NULL, NULL, &desc->perm)) {
1622 error("Failed to parse characteristic properties");
1626 queue_push_tail(desc->service->descs, desc);
1635 static bool check_service_path(GDBusProxy *proxy,
1636 struct external_service *service)
1638 const char *service_path;
1640 if (!parse_path(proxy, "Service", &service_path))
1643 return g_strcmp0(service_path, service->path) == 0;
1646 static struct external_service *create_service(struct gatt_app *app,
1650 struct external_service *service;
1652 if (!path || !g_str_has_prefix(path, "/"))
1655 service = queue_find(app->services, match_service_by_path, path);
1657 error("Duplicated service: %s", path);
1661 service = new0(struct external_service, 1);
1665 service->path = g_strdup(path);
1669 service->proxy = g_dbus_proxy_ref(proxy);
1670 service->chrcs = queue_new();
1671 service->descs = queue_new();
1673 /* Add 1 for the service declaration */
1674 if (!incr_attr_count(service, 1)) {
1675 error("Failed to increment attribute count");
1679 queue_push_tail(app->services, service);
1684 service_free(service);
1688 static void proxy_added_cb(GDBusProxy *proxy, void *user_data)
1690 struct gatt_app *app = user_data;
1691 const char *iface, *path;
1696 iface = g_dbus_proxy_get_interface(proxy);
1697 path = g_dbus_proxy_get_path(proxy);
1699 if (g_strcmp0(iface, GATT_SERVICE_IFACE) == 0) {
1700 struct external_service *service;
1702 service = create_service(app, proxy, path);
1707 } else if (g_strcmp0(iface, GATT_CHRC_IFACE) == 0) {
1708 struct external_chrc *chrc;
1710 chrc = chrc_create(app, proxy, path);
1715 } else if (g_strcmp0(iface, GATT_DESC_IFACE) == 0) {
1716 struct external_desc *desc;
1718 desc = desc_create(app, proxy);
1724 DBG("Ignoring unrelated interface: %s", iface);
1728 DBG("Object added: path: %s, iface: %s", path, iface);
1731 static void proxy_removed_cb(GDBusProxy *proxy, void *user_data)
1733 struct gatt_app *app = user_data;
1734 struct external_service *service;
1737 path = g_dbus_proxy_get_path(proxy);
1739 service = queue_remove_if(app->services, match_service_by_path,
1744 DBG("Proxy removed - removing service: %s", service->path);
1746 service_free(service);
1749 static bool parse_uuid(GDBusProxy *proxy, bt_uuid_t *uuid)
1751 DBusMessageIter iter;
1753 const char *uuidstr;
1755 if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
1758 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1761 dbus_message_iter_get_basic(&iter, &uuidstr);
1763 if (bt_string_to_uuid(uuid, uuidstr) < 0)
1766 /* GAP & GATT services are created and managed by BlueZ */
1767 bt_uuid16_create(&tmp, UUID_GAP);
1768 if (!bt_uuid_cmp(&tmp, uuid)) {
1769 error("GAP service must be handled by BlueZ");
1773 bt_uuid16_create(&tmp, UUID_GATT);
1774 if (!bt_uuid_cmp(&tmp, uuid)) {
1775 error("GATT service must be handled by BlueZ");
1782 static bool parse_primary(GDBusProxy *proxy, bool *primary)
1784 DBusMessageIter iter;
1787 if (!g_dbus_proxy_get_property(proxy, "Primary", &iter))
1790 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
1793 dbus_message_iter_get_basic(&iter, &val);
1800 static uint8_t dbus_error_to_att_ecode(const char *error_name)
1803 if (strcmp(error_name, "org.bluez.Error.Failed") == 0)
1804 return 0x80; /* For now return this "application error" */
1806 if (strcmp(error_name, "org.bluez.Error.NotSupported") == 0)
1807 return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
1809 if (strcmp(error_name, "org.bluez.Error.NotAuthorized") == 0)
1810 return BT_ATT_ERROR_AUTHORIZATION;
1812 if (strcmp(error_name, "org.bluez.Error.InvalidValueLength") == 0)
1813 return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
1815 if (strcmp(error_name, "org.bluez.Error.InProgress") == 0)
1816 return BT_ERROR_ALREADY_IN_PROGRESS;
1821 static void read_reply_cb(DBusMessage *message, void *user_data)
1823 struct pending_op *op = user_data;
1825 DBusMessageIter iter, array;
1827 uint8_t *value = NULL;
1830 if (!op->owner_queue) {
1831 DBG("Pending read was canceled when object got removed");
1835 dbus_error_init(&err);
1837 if (dbus_set_error_from_message(&err, message) == TRUE) {
1838 DBG("Failed to read value: %s: %s", err.name, err.message);
1839 ecode = dbus_error_to_att_ecode(err.name);
1840 ecode = ecode ? ecode : BT_ATT_ERROR_READ_NOT_PERMITTED;
1841 dbus_error_free(&err);
1845 dbus_message_iter_init(message, &iter);
1847 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1849 * Return not supported for this, as the external app basically
1850 * doesn't properly support reading from this characteristic.
1852 ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
1853 error("Invalid return value received for \"ReadValue\"");
1857 dbus_message_iter_recurse(&iter, &array);
1858 dbus_message_iter_get_fixed_array(&array, &value, &len);
1861 ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
1867 /* Truncate the value if it's too large */
1868 len = MIN(BT_ATT_MAX_VALUE_LEN, len);
1869 value = len ? value : NULL;
1872 gatt_db_attribute_read_result(op->attrib, op->id, ecode, value, len);
1875 static void pending_op_free(void *data)
1877 struct pending_op *op = data;
1879 if (op->owner_queue)
1880 queue_remove(op->owner_queue, op);
1885 #ifdef __TIZEN_PATCH__
1886 static struct pending_op *pending_read_new(struct queue *owner_queue,
1887 struct gatt_db_attribute *attrib,
1891 static struct pending_op *pending_read_new(struct queue *owner_queue,
1892 struct gatt_db_attribute *attrib,
1896 struct pending_op *op;
1897 #ifdef __TIZEN_PATCH__
1899 uint8_t bdaddr_type;
1902 op = new0(struct pending_op, 1);
1906 #ifdef __TIZEN_PATCH__
1907 if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
1913 op->owner_queue = owner_queue;
1914 #ifdef __TIZEN_PATCH__
1915 memcpy(&op->bdaddr, &bdaddr, sizeof(bdaddr_t));
1916 op->bdaddr_type = bdaddr_type;
1919 op->attrib = attrib;
1921 queue_push_tail(owner_queue, op);
1926 #ifdef __TIZEN_PATCH__
1927 static void read_setup_cb(DBusMessageIter *iter, void *user_data)
1929 struct pending_op *op = user_data;
1930 char dstaddr[18] = { 0 };
1931 char *addr_value = NULL;
1932 uint16_t offset = 0;
1934 ba2str(&op->bdaddr, dstaddr);
1935 addr_value = g_strdup(dstaddr);
1937 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
1940 dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
1943 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
1948 #ifdef __TIZEN_PATCH__
1949 static void send_read(struct gatt_db_attribute *attrib, struct bt_att *att,
1950 GDBusProxy *proxy, struct queue *owner_queue,
1953 static void send_read(struct gatt_db_attribute *attrib, GDBusProxy *proxy,
1954 struct queue *owner_queue,
1958 struct pending_op *op;
1959 uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
1961 #ifdef __TIZEN_PATCH__
1962 op = pending_read_new(owner_queue, attrib, att, id);
1964 op = pending_read_new(owner_queue, attrib, id);
1967 error("Failed to allocate memory for pending read call");
1968 ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
1972 #ifdef __TIZEN_PATCH__
1973 if (g_dbus_proxy_method_call(proxy, "ReadValue", read_setup_cb, read_reply_cb,
1974 op, pending_op_free) == TRUE)
1976 if (g_dbus_proxy_method_call(proxy, "ReadValue", NULL, read_reply_cb,
1977 op, pending_op_free) == TRUE)
1981 pending_op_free(op);
1984 gatt_db_attribute_read_result(attrib, id, ecode, NULL, 0);
1987 static void write_setup_cb(DBusMessageIter *iter, void *user_data)
1989 struct pending_op *op = user_data;
1990 DBusMessageIter array;
1991 #ifdef __TIZEN_PATCH__
1992 char dstaddr[18] = { 0 };
1993 char *addr_value = NULL;
1994 uint16_t offset = 0;
1997 #ifdef __TIZEN_PATCH__
1998 ba2str(&op->bdaddr, dstaddr);
1999 addr_value = g_strdup(dstaddr);
2001 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
2004 dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
2007 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
2011 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
2012 dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
2013 &op->data.iov_base, op->data.iov_len);
2014 dbus_message_iter_close_container(iter, &array);
2017 static void write_reply_cb(DBusMessage *message, void *user_data)
2019 struct pending_op *op = user_data;
2021 DBusMessageIter iter;
2024 if (!op->owner_queue) {
2025 DBG("Pending write was canceled when object got removed");
2029 dbus_error_init(&err);
2031 if (dbus_set_error_from_message(&err, message) == TRUE) {
2032 DBG("Failed to write value: %s: %s", err.name, err.message);
2033 ecode = dbus_error_to_att_ecode(err.name);
2034 ecode = ecode ? ecode : BT_ATT_ERROR_WRITE_NOT_PERMITTED;
2035 dbus_error_free(&err);
2039 dbus_message_iter_init(message, &iter);
2040 if (dbus_message_iter_has_next(&iter)) {
2042 * Return not supported for this, as the external app basically
2043 * doesn't properly support the "WriteValue" API.
2045 ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
2046 error("Invalid return value received for \"WriteValue\"");
2050 gatt_db_attribute_write_result(op->attrib, op->id, ecode);
2053 #ifdef __TIZEN_PATCH__
2054 static struct pending_op *pending_write_new(struct queue *owner_queue,
2055 struct gatt_db_attribute *attrib, struct bt_att *att,
2057 const uint8_t *value,
2060 static struct pending_op *pending_write_new(struct queue *owner_queue,
2061 struct gatt_db_attribute *attrib,
2063 const uint8_t *value,
2067 struct pending_op *op;
2068 #ifdef __TIZEN_PATCH__
2070 uint8_t bdaddr_type;
2073 op = new0(struct pending_op, 1);
2076 #ifdef __TIZEN_PATCH__
2077 if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
2083 op->data.iov_base = (uint8_t *) value;
2084 op->data.iov_len = len;
2085 #ifdef __TIZEN_PATCH__
2086 memcpy(&op->bdaddr, &bdaddr, sizeof(bdaddr_t));
2087 op->bdaddr_type = bdaddr_type;
2090 op->owner_queue = owner_queue;
2091 op->attrib = attrib;
2093 queue_push_tail(owner_queue, op);
2098 #ifdef __TIZEN_PATCH__
2099 static void send_write(struct gatt_db_attribute *attrib, struct bt_att *att,
2100 GDBusProxy *proxy, struct queue *owner_queue,
2101 unsigned int id, const uint8_t *value, size_t len)
2103 static void send_write(struct gatt_db_attribute *attrib, GDBusProxy *proxy,
2104 struct queue *owner_queue,
2106 const uint8_t *value, size_t len)
2109 struct pending_op *op;
2110 uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
2112 #ifdef __TIZEN_PATCH__
2113 op = pending_write_new(owner_queue, attrib, att, id, value, len);
2115 op = pending_write_new(owner_queue, attrib, id, value, len);
2118 error("Failed to allocate memory for pending read call");
2119 ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
2123 if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup_cb,
2125 pending_op_free) == TRUE)
2128 pending_op_free(op);
2131 gatt_db_attribute_write_result(attrib, id, ecode);
2134 static uint32_t permissions_from_props(uint8_t props, uint8_t ext_props)
2138 if (props & BT_GATT_CHRC_PROP_WRITE ||
2139 props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP ||
2140 ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE ||
2141 ext_props & BT_GATT_CHRC_EXT_PROP_ENC_WRITE ||
2142 ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_WRITE)
2143 perm |= BT_ATT_PERM_WRITE;
2145 if (props & BT_GATT_CHRC_PROP_READ ||
2146 ext_props & BT_GATT_CHRC_EXT_PROP_ENC_READ ||
2147 ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_READ)
2148 perm |= BT_ATT_PERM_READ;
2150 if (ext_props & BT_GATT_CHRC_EXT_PROP_ENC_READ)
2151 perm |= BT_ATT_PERM_READ_ENCRYPT;
2153 if (ext_props & BT_GATT_CHRC_EXT_PROP_ENC_WRITE)
2154 perm |= BT_ATT_PERM_WRITE_ENCRYPT;
2156 if (ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_READ)
2157 perm |= BT_ATT_PERM_READ_AUTHEN;
2159 if (ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_WRITE)
2160 perm |= BT_ATT_PERM_WRITE_AUTHEN;
2165 static uint8_t ccc_write_cb(uint16_t value, void *user_data)
2167 struct external_chrc *chrc = user_data;
2169 DBG("External CCC write received with value: 0x%04x", value);
2171 /* Notifications/indications disabled */
2173 if (!chrc->ntfy_cnt)
2176 if (__sync_sub_and_fetch(&chrc->ntfy_cnt, 1))
2180 * Send request to stop notifying. This is best-effort
2181 * operation, so simply ignore the return the value.
2183 g_dbus_proxy_method_call(chrc->proxy, "StopNotify", NULL,
2188 if (chrc->ntfy_cnt == UINT_MAX) {
2189 /* Maximum number of per-device CCC descriptors configured */
2190 return BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
2193 /* Don't support undefined CCC values yet */
2195 (value == 1 && !(chrc->props & BT_GATT_CHRC_PROP_NOTIFY)) ||
2196 (value == 2 && !(chrc->props & BT_GATT_CHRC_PROP_INDICATE)))
2197 return BT_ERROR_CCC_IMPROPERLY_CONFIGURED;
2200 * Always call StartNotify for an incoming enable and ignore the return
2203 if (g_dbus_proxy_method_call(chrc->proxy,
2204 "StartNotify", NULL, NULL,
2205 NULL, NULL) == FALSE)
2206 return BT_ATT_ERROR_UNLIKELY;
2208 __sync_fetch_and_add(&chrc->ntfy_cnt, 1);
2213 static void property_changed_cb(GDBusProxy *proxy, const char *name,
2214 DBusMessageIter *iter, void *user_data)
2216 struct external_chrc *chrc = user_data;
2217 DBusMessageIter array;
2218 uint8_t *value = NULL;
2220 #ifdef __TIZEN_PATCH__
2221 bool enable = FALSE;
2222 const bdaddr_t *unicast_addr = NULL;
2225 #ifdef __TIZEN_PATCH__
2226 if (strcmp(name, "Value") == 0) {
2227 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
2228 DBG("Malformed \"Value\" property received");
2232 dbus_message_iter_recurse(iter, &array);
2233 dbus_message_iter_get_fixed_array(&array, &value, &len);
2236 DBG("Malformed \"Value\" property received");
2240 /* Truncate the value if it's too large */
2241 len = MIN(BT_ATT_MAX_VALUE_LEN, len);
2242 value = len ? value : NULL;
2243 } else if (strcmp(name, "Notifying") == 0) {
2244 gboolean notify_indicate = FALSE;
2246 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
2247 DBG("Malformed \"Notifying\" property received");
2251 dbus_message_iter_get_basic(iter, ¬ify_indicate);
2253 DBG("Set Notification %d", notify_indicate);
2254 /* Set notification/indication */
2255 set_ccc_notify_indicate(chrc->ccc, notify_indicate);
2257 } else if (strcmp(name, "Unicast") == 0) {
2258 const char *address = NULL;
2259 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
2260 DBG("Malformed \"Value\" property received");
2264 dbus_message_iter_get_basic(iter, &address);
2267 /* Set the address for unicast notification/indication */
2268 set_ccc_unicast_address(chrc->ccc, address);
2274 enable = get_ccc_notify_indicate(chrc->ccc);
2277 unicast_addr = get_ccc_unicast_address(chrc->ccc);
2279 if (unicast_addr && bacmp(unicast_addr, BDADDR_ANY)) {
2280 send_unicast_notification_indication_to_device(proxy,
2281 chrc->service->app->database,
2282 gatt_db_attribute_get_handle(chrc->attrib),
2284 gatt_db_attribute_get_handle(chrc->ccc),
2285 chrc->props & BT_GATT_CHRC_PROP_INDICATE,
2287 /* reset the unicast address */
2288 set_ccc_unicast_address(chrc->ccc, NULL);
2290 send_notification_indication_to_devices(proxy,
2291 chrc->service->app->database,
2292 gatt_db_attribute_get_handle(chrc->attrib),
2294 gatt_db_attribute_get_handle(chrc->ccc),
2295 chrc->props & BT_GATT_CHRC_PROP_INDICATE);
2298 set_ccc_notify_indicate(chrc->ccc, FALSE);
2301 if (strcmp(name, "Value"))
2304 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
2305 DBG("Malformed \"Value\" property received");
2309 dbus_message_iter_recurse(iter, &array);
2310 dbus_message_iter_get_fixed_array(&array, &value, &len);
2313 DBG("Malformed \"Value\" property received");
2317 /* Truncate the value if it's too large */
2318 len = MIN(BT_ATT_MAX_VALUE_LEN, len);
2319 value = len ? value : NULL;
2321 send_notification_to_devices(chrc->service->app->database,
2322 gatt_db_attribute_get_handle(chrc->attrib),
2324 gatt_db_attribute_get_handle(chrc->ccc),
2325 chrc->props & BT_GATT_CHRC_PROP_INDICATE);
2329 static bool database_add_ccc(struct external_service *service,
2330 struct external_chrc *chrc)
2332 if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY) &&
2333 !(chrc->props & BT_GATT_CHRC_PROP_INDICATE))
2336 chrc->ccc = service_add_ccc(service->attrib, service->app->database,
2337 ccc_write_cb, chrc, NULL);
2339 error("Failed to create CCC entry for characteristic");
2343 if (g_dbus_proxy_set_property_watch(chrc->proxy, property_changed_cb,
2345 error("Failed to set up property watch for characteristic");
2349 DBG("Created CCC entry for characteristic");
2354 static void cep_write_cb(struct gatt_db_attribute *attrib, int err,
2358 DBG("Failed to store CEP value in the database");
2360 DBG("Stored CEP value in the database");
2363 static bool database_add_cep(struct external_service *service,
2364 struct external_chrc *chrc)
2366 struct gatt_db_attribute *cep;
2370 if (!chrc->ext_props)
2373 bt_uuid16_create(&uuid, GATT_CHARAC_EXT_PROPER_UUID);
2374 cep = gatt_db_service_add_descriptor(service->attrib, &uuid,
2378 error("Failed to create CEP entry for characteristic");
2382 memset(value, 0, sizeof(value));
2383 value[0] = chrc->ext_props;
2385 if (!gatt_db_attribute_write(cep, 0, value, sizeof(value), 0, NULL,
2386 cep_write_cb, NULL)) {
2387 DBG("Failed to store CEP value in the database");
2391 DBG("Created CEP entry for characteristic");
2396 static void desc_read_cb(struct gatt_db_attribute *attrib,
2397 unsigned int id, uint16_t offset,
2398 uint8_t opcode, struct bt_att *att,
2401 struct external_desc *desc = user_data;
2403 if (desc->attrib != attrib) {
2404 error("Read callback called with incorrect attribute");
2407 #ifdef __TIZEN_PATCH__
2408 send_read(attrib, att, desc->proxy, desc->pending_reads, id);
2410 send_read(attrib, desc->proxy, desc->pending_reads, id);
2414 static void desc_write_cb(struct gatt_db_attribute *attrib,
2415 unsigned int id, uint16_t offset,
2416 const uint8_t *value, size_t len,
2417 uint8_t opcode, struct bt_att *att,
2420 struct external_desc *desc = user_data;
2422 if (desc->attrib != attrib) {
2423 error("Read callback called with incorrect attribute");
2427 #ifdef __TIZEN_PATCH__
2428 send_write(attrib, att, desc->proxy, desc->pending_writes, id, value, len);
2430 send_write(attrib, desc->proxy, desc->pending_writes, id, value, len);
2434 static bool database_add_desc(struct external_service *service,
2435 struct external_desc *desc)
2439 if (!parse_uuid(desc->proxy, &uuid)) {
2440 error("Failed to read \"UUID\" property of descriptor");
2444 desc->attrib = gatt_db_service_add_descriptor(service->attrib, &uuid,
2447 desc_write_cb, desc);
2448 if (!desc->attrib) {
2449 error("Failed to create descriptor entry in database");
2453 desc->handled = true;
2458 static void chrc_read_cb(struct gatt_db_attribute *attrib,
2459 unsigned int id, uint16_t offset,
2460 uint8_t opcode, struct bt_att *att,
2463 struct external_chrc *chrc = user_data;
2465 if (chrc->attrib != attrib) {
2466 error("Read callback called with incorrect attribute");
2470 #ifdef __TIZEN_PATCH__
2471 send_read(attrib, att, chrc->proxy, chrc->pending_reads, id);
2473 send_read(attrib, chrc->proxy, chrc->pending_reads, id);
2477 #ifndef __TIZEN_PATCH__
2478 static void write_without_response_setup_cb(DBusMessageIter *iter,
2481 struct iovec *iov = user_data;
2482 DBusMessageIter array;
2484 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
2485 dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
2486 &iov->iov_base, iov->iov_len);
2487 dbus_message_iter_close_container(iter, &array);
2490 static void send_write_without_response(struct gatt_db_attribute *attrib,
2491 GDBusProxy *proxy, unsigned int id,
2492 const uint8_t *value, size_t len)
2497 iov.iov_base = (uint8_t *) value;
2500 if (!g_dbus_proxy_method_call(proxy, "WriteValue",
2501 write_without_response_setup_cb,
2503 ecode = BT_ATT_ERROR_UNLIKELY;
2505 gatt_db_attribute_write_result(attrib, id, ecode);
2509 static void chrc_write_cb(struct gatt_db_attribute *attrib,
2510 unsigned int id, uint16_t offset,
2511 const uint8_t *value, size_t len,
2512 uint8_t opcode, struct bt_att *att,
2515 struct external_chrc *chrc = user_data;
2517 if (chrc->attrib != attrib) {
2518 error("Write callback called with incorrect attribute");
2522 #ifdef __TIZEN_PATCH__
2523 if ((!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) &&
2524 opcode == BT_ATT_OP_WRITE_CMD) ||
2525 (!(chrc->props & BT_GATT_CHRC_PROP_WRITE) &&
2526 opcode == BT_ATT_OP_WRITE_REQ)) {
2527 uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
2528 error("Property and opcode is not matched");
2529 gatt_db_attribute_write_result(attrib, id, ecode);
2533 send_write(attrib, att, chrc->proxy, chrc->pending_writes, id, value, len);
2535 if (chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) {
2536 send_write_without_response(attrib, chrc->proxy, id, value,
2541 send_write(attrib, chrc->proxy, chrc->pending_writes, id, value, len);
2545 #ifdef __TIZEN_PATCH__
2546 static bool database_check_ccc_desc(struct external_desc *desc)
2548 bt_uuid_t uuid, uuid_ccc;
2550 if (!parse_uuid(desc->proxy, &uuid)) {
2551 error("Failed to read \"UUID\" property of descriptor");
2555 bt_uuid16_create(&uuid_ccc, GATT_CLIENT_CHARAC_CFG_UUID);
2556 if (bt_uuid_cmp(&uuid, &uuid_ccc) == 0)
2563 static bool database_add_chrc(struct external_service *service,
2564 struct external_chrc *chrc)
2568 const struct queue_entry *entry;
2570 if (!parse_uuid(chrc->proxy, &uuid)) {
2571 error("Failed to read \"UUID\" property of characteristic");
2575 if (!check_service_path(chrc->proxy, service)) {
2576 error("Invalid service path for characteristic");
2581 * TODO: Once shared/gatt-server properly supports permission checks,
2582 * set the permissions based on a D-Bus property of the external
2585 perm = permissions_from_props(chrc->props, chrc->ext_props);
2586 chrc->attrib = gatt_db_service_add_characteristic(service->attrib,
2588 chrc->props, chrc_read_cb,
2589 chrc_write_cb, chrc);
2590 if (!chrc->attrib) {
2591 error("Failed to create characteristic entry in database");
2595 #ifndef __TIZEN_PATCH__
2596 /* Existing implementation adds CCC descriptor by default
2597 * if notification and indication properties are set. But as per the requirment
2598 * CCCD shall be added by the application */
2599 if (!database_add_ccc(service, chrc))
2603 if (!database_add_cep(service, chrc))
2606 /* Handle the descriptors that belong to this characteristic. */
2607 for (entry = queue_get_entries(service->descs); entry;
2608 entry = entry->next) {
2609 struct external_desc *desc = entry->data;
2611 if (desc->handled || g_strcmp0(desc->chrc_path, chrc->path))
2614 #ifdef __TIZEN_PATCH__
2615 /* Check if Application wants to add CCC and use existing
2616 * implemenation to add CCC descriptors */
2617 if (database_check_ccc_desc(desc)) {
2618 if (!database_add_ccc(service, chrc)) {
2619 chrc->attrib = NULL;
2622 desc->attrib = chrc->ccc;
2623 desc->handled = true;
2624 } else if (!database_add_desc(service, desc)) {
2625 chrc->attrib = NULL;
2626 error("Failed to create descriptor entry");
2630 if (!database_add_desc(service, desc)) {
2631 chrc->attrib = NULL;
2632 error("Failed to create descriptor entry");
2641 static bool match_desc_unhandled(const void *a, const void *b)
2643 const struct external_desc *desc = a;
2645 return !desc->handled;
2648 static bool database_add_service(struct external_service *service)
2652 const struct queue_entry *entry;
2654 if (!parse_uuid(service->proxy, &uuid)) {
2655 error("Failed to read \"UUID\" property of service");
2659 if (!parse_primary(service->proxy, &primary)) {
2660 error("Failed to read \"Primary\" property of service");
2664 service->attrib = gatt_db_add_service(service->app->database->db, &uuid,
2665 primary, service->attr_cnt);
2666 if (!service->attrib)
2669 entry = queue_get_entries(service->chrcs);
2671 struct external_chrc *chrc = entry->data;
2673 if (!database_add_chrc(service, chrc)) {
2674 error("Failed to add characteristic");
2678 entry = entry->next;
2681 /* If there are any unhandled descriptors, return an error */
2682 if (queue_find(service->descs, match_desc_unhandled, NULL)) {
2683 error("Found descriptor with no matching characteristic!");
2687 gatt_db_service_set_active(service->attrib, true);
2692 gatt_db_remove_service(service->app->database->db, service->attrib);
2693 service->attrib = NULL;
2698 static bool database_add_app(struct gatt_app *app)
2700 const struct queue_entry *entry;
2702 if (queue_isempty(app->services))
2705 entry = queue_get_entries(app->services);
2707 if (!database_add_service(entry->data)) {
2708 error("Failed to add service");
2712 entry = entry->next;
2718 static void client_ready_cb(GDBusClient *client, void *user_data)
2720 struct gatt_app *app = user_data;
2724 if (!app->services || app->failed) {
2725 error("No valid external GATT objects found");
2727 reply = btd_error_failed(app->reg,
2728 "No valid service object found");
2732 if (!database_add_app(app)) {
2733 error("Failed to create GATT service entry in local database");
2735 reply = btd_error_failed(app->reg,
2736 "Failed to create entry in database");
2740 DBG("GATT application registered: %s:%s", app->owner, app->path);
2742 reply = dbus_message_new_method_return(app->reg);
2745 g_dbus_send_message(btd_get_dbus_connection(), reply);
2746 dbus_message_unref(app->reg);
2753 static struct gatt_app *create_app(DBusConnection *conn, DBusMessage *msg,
2756 struct gatt_app *app;
2757 const char *sender = dbus_message_get_sender(msg);
2759 if (!path || !g_str_has_prefix(path, "/"))
2762 app = new0(struct gatt_app, 1);
2764 app->client = g_dbus_client_new_full(conn, sender, path, path);
2768 app->owner = g_strdup(sender);
2772 app->path = g_strdup(path);
2776 app->services = queue_new();
2777 app->reg = dbus_message_ref(msg);
2779 g_dbus_client_set_disconnect_watch(app->client, client_disconnect_cb,
2781 g_dbus_client_set_proxy_handlers(app->client, proxy_added_cb,
2782 proxy_removed_cb, NULL, app);
2783 g_dbus_client_set_ready_watch(app->client, client_ready_cb, app);
2792 static DBusMessage *manager_register_app(DBusConnection *conn,
2793 DBusMessage *msg, void *user_data)
2795 struct btd_gatt_database *database = user_data;
2796 const char *sender = dbus_message_get_sender(msg);
2797 DBusMessageIter args;
2799 struct gatt_app *app;
2800 struct svc_match_data match_data;
2802 if (!dbus_message_iter_init(msg, &args))
2803 return btd_error_invalid_args(msg);
2805 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
2806 return btd_error_invalid_args(msg);
2808 dbus_message_iter_get_basic(&args, &path);
2810 match_data.path = path;
2811 match_data.sender = sender;
2813 if (queue_find(database->apps, match_app, &match_data))
2814 return btd_error_already_exists(msg);
2816 dbus_message_iter_next(&args);
2817 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
2818 return btd_error_invalid_args(msg);
2820 app = create_app(conn, msg, path);
2822 return btd_error_failed(msg, "Failed to register application");
2824 DBG("Registering application: %s:%s", sender, path);
2826 app->database = database;
2827 queue_push_tail(database->apps, app);
2832 static DBusMessage *manager_unregister_app(DBusConnection *conn,
2833 DBusMessage *msg, void *user_data)
2835 struct btd_gatt_database *database = user_data;
2836 const char *sender = dbus_message_get_sender(msg);
2838 DBusMessageIter args;
2839 struct gatt_app *app;
2840 struct svc_match_data match_data;
2842 if (!dbus_message_iter_init(msg, &args))
2843 return btd_error_invalid_args(msg);
2845 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
2846 return btd_error_invalid_args(msg);
2848 dbus_message_iter_get_basic(&args, &path);
2850 match_data.path = path;
2851 match_data.sender = sender;
2853 app = queue_remove_if(database->apps, match_app, &match_data);
2855 return btd_error_does_not_exist(msg);
2859 return dbus_message_new_method_return(msg);
2862 static void profile_exited(DBusConnection *conn, void *user_data)
2864 struct external_profile *profile = user_data;
2866 DBG("\"%s\" exited", profile->owner);
2870 queue_remove(profile->database->profiles, profile);
2872 profile_free(profile);
2875 static int profile_device_probe(struct btd_service *service)
2877 struct btd_profile *p = btd_service_get_profile(service);
2879 DBG("%s probed", p->name);
2884 static void profile_device_remove(struct btd_service *service)
2886 struct btd_profile *p = btd_service_get_profile(service);
2888 DBG("%s removed", p->name);
2891 static int profile_add(struct external_profile *profile, const char *uuid)
2893 struct btd_profile *p;
2895 p = new0(struct btd_profile, 1);
2897 /* Assign directly to avoid having extra fields */
2898 p->name = (const void *) g_strdup_printf("%s%s/%s", profile->owner,
2899 profile->path, uuid);
2905 p->remote_uuid = (const void *) g_strdup(uuid);
2906 if (!p->remote_uuid) {
2907 g_free((void *) p->name);
2912 p->device_probe = profile_device_probe;
2913 p->device_remove = profile_device_remove;
2914 p->auto_connect = true;
2917 queue_push_tail(profile->profiles, p);
2919 DBG("Added \"%s\"", p->name);
2924 static void add_profile(void *data, void *user_data)
2926 struct btd_adapter *adapter = user_data;
2928 btd_profile_register(data);
2929 adapter_add_profile(adapter, data);
2932 static int profile_create(DBusConnection *conn,
2933 struct btd_gatt_database *database,
2934 const char *sender, const char *path,
2935 DBusMessageIter *iter)
2937 struct external_profile *profile;
2938 DBusMessageIter uuids;
2940 if (!path || !g_str_has_prefix(path, "/"))
2943 profile = new0(struct external_profile, 1);
2945 profile->owner = g_strdup(sender);
2946 if (!profile->owner)
2949 profile->path = g_strdup(path);
2953 profile->profiles = queue_new();
2954 profile->database = database;
2955 profile->id = g_dbus_add_disconnect_watch(conn, sender, profile_exited,
2958 dbus_message_iter_recurse(iter, &uuids);
2960 while (dbus_message_iter_get_arg_type(&uuids) == DBUS_TYPE_STRING) {
2963 dbus_message_iter_get_basic(&uuids, &uuid);
2965 if (profile_add(profile, uuid) < 0)
2968 dbus_message_iter_next(&uuids);
2971 if (queue_isempty(profile->profiles))
2974 queue_foreach(profile->profiles, add_profile, database->adapter);
2975 queue_push_tail(database->profiles, profile);
2980 profile_free(profile);
2984 static bool match_profile(const void *a, const void *b)
2986 const struct external_profile *profile = a;
2987 const struct svc_match_data *data = b;
2989 return g_strcmp0(profile->path, data->path) == 0 &&
2990 g_strcmp0(profile->owner, data->sender) == 0;
2993 static DBusMessage *manager_register_profile(DBusConnection *conn,
2994 DBusMessage *msg, void *user_data)
2996 struct btd_gatt_database *database = user_data;
2997 const char *sender = dbus_message_get_sender(msg);
2998 DBusMessageIter args;
3000 struct svc_match_data match_data;
3002 DBG("sender %s", sender);
3004 if (!dbus_message_iter_init(msg, &args))
3005 return btd_error_invalid_args(msg);
3007 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
3008 return btd_error_invalid_args(msg);
3010 dbus_message_iter_get_basic(&args, &path);
3012 match_data.path = path;
3013 match_data.sender = sender;
3015 if (queue_find(database->profiles, match_profile, &match_data))
3016 return btd_error_already_exists(msg);
3018 dbus_message_iter_next(&args);
3019 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
3020 return btd_error_invalid_args(msg);
3022 if (profile_create(conn, database, sender, path, &args) < 0)
3023 return btd_error_failed(msg, "Failed to register profile");
3025 return dbus_message_new_method_return(msg);
3028 static DBusMessage *manager_unregister_profile(DBusConnection *conn,
3029 DBusMessage *msg, void *user_data)
3031 struct btd_gatt_database *database = user_data;
3032 const char *sender = dbus_message_get_sender(msg);
3034 DBusMessageIter args;
3035 struct external_profile *profile;
3036 struct svc_match_data match_data;
3038 if (!dbus_message_iter_init(msg, &args))
3039 return btd_error_invalid_args(msg);
3041 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
3042 return btd_error_invalid_args(msg);
3044 dbus_message_iter_get_basic(&args, &path);
3046 match_data.path = path;
3047 match_data.sender = sender;
3049 profile = queue_remove_if(database->profiles, match_profile,
3052 return btd_error_does_not_exist(msg);
3054 profile_free(profile);
3056 return dbus_message_new_method_return(msg);
3059 static const GDBusMethodTable manager_methods[] = {
3060 #ifdef __TIZEN_PATCH__
3061 { GDBUS_ASYNC_METHOD("RegisterApplication",
3062 GDBUS_ARGS({ "application", "o" },
3063 { "options", "a{sv}" }), NULL,
3064 manager_register_app) },
3065 { GDBUS_ASYNC_METHOD("UnregisterApplication",
3066 GDBUS_ARGS({ "application", "o" }),
3067 NULL, manager_unregister_app) },
3068 { GDBUS_ASYNC_METHOD("RegisterProfile",
3069 GDBUS_ARGS({ "profile", "o" }, { "UUIDs", "as" },
3070 { "options", "a{sv}" }), NULL,
3071 manager_register_profile) },
3072 { GDBUS_ASYNC_METHOD("UnregisterProfile",
3073 GDBUS_ARGS({ "profile", "o" }),
3074 NULL, manager_unregister_profile) },
3077 { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterApplication",
3078 GDBUS_ARGS({ "application", "o" },
3079 { "options", "a{sv}" }), NULL,
3080 manager_register_app) },
3081 { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterApplication",
3082 GDBUS_ARGS({ "application", "o" }),
3083 NULL, manager_unregister_app) },
3084 { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterProfile",
3085 GDBUS_ARGS({ "profile", "o" }, { "UUIDs", "as" },
3086 { "options", "a{sv}" }), NULL,
3087 manager_register_profile) },
3088 { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterProfile",
3089 GDBUS_ARGS({ "profile", "o" }),
3090 NULL, manager_unregister_profile) },
3095 struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter)
3097 struct btd_gatt_database *database;
3098 GError *gerr = NULL;
3099 const bdaddr_t *addr;
3104 database = new0(struct btd_gatt_database, 1);
3105 database->adapter = btd_adapter_ref(adapter);
3106 database->db = gatt_db_new();
3107 database->device_states = queue_new();
3108 database->apps = queue_new();
3109 database->profiles = queue_new();
3110 database->ccc_callbacks = queue_new();
3112 database->db_id = gatt_db_register(database->db, gatt_db_service_added,
3113 gatt_db_service_removed,
3115 if (!database->db_id)
3118 addr = btd_adapter_get_address(adapter);
3119 database->le_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,
3120 BT_IO_OPT_SOURCE_BDADDR, addr,
3121 BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
3122 BT_IO_OPT_CID, ATT_CID,
3123 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
3125 if (!database->le_io) {
3126 error("Failed to start listening: %s", gerr->message);
3132 database->l2cap_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,
3133 BT_IO_OPT_SOURCE_BDADDR, addr,
3134 BT_IO_OPT_PSM, ATT_PSM,
3135 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
3137 if (database->l2cap_io == NULL) {
3138 error("Failed to start listening: %s", gerr->message);
3143 if (g_dbus_register_interface(btd_get_dbus_connection(),
3144 adapter_get_path(adapter),
3146 manager_methods, NULL, NULL,
3148 DBG("GATT Manager registered for adapter: %s",
3149 adapter_get_path(adapter));
3151 register_core_services(database);
3156 gatt_database_free(database);
3161 void btd_gatt_database_destroy(struct btd_gatt_database *database)
3166 g_dbus_unregister_interface(btd_get_dbus_connection(),
3167 adapter_get_path(database->adapter),
3168 GATT_MANAGER_IFACE);
3170 gatt_database_free(database);
3173 struct gatt_db *btd_gatt_database_get_db(struct btd_gatt_database *database)
3178 return database->db;