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.
29 #include "lib/bluetooth.h"
31 #include "lib/sdp_lib.h"
33 #include "btio/btio.h"
34 #include "gdbus/gdbus.h"
35 #include "src/shared/util.h"
36 #include "src/shared/queue.h"
37 #include "src/shared/io.h"
38 #include "src/shared/att.h"
39 #include "src/shared/gatt-db.h"
40 #include "src/shared/gatt-server.h"
45 #include "gatt-database.h"
46 #include "dbus-common.h"
58 #define GATT_MANAGER_IFACE "org.bluez.GattManager1"
59 #define GATT_PROFILE_IFACE "org.bluez.GattProfile1"
60 #define GATT_SERVICE_IFACE "org.bluez.GattService1"
61 #define GATT_CHRC_IFACE "org.bluez.GattCharacteristic1"
62 #define GATT_DESC_IFACE "org.bluez.GattDescriptor1"
64 #define UUID_GAP 0x1800
65 #define UUID_GATT 0x1801
68 #define MIN(a, b) ((a) < (b) ? (a) : (b))
72 struct btd_gatt_database *database;
74 struct gatt_db_attribute *attr;
77 struct btd_gatt_database {
78 struct btd_adapter *adapter;
83 struct queue *records;
84 struct queue *device_states;
85 struct queue *ccc_callbacks;
86 struct gatt_db_attribute *svc_chngd;
87 struct gatt_db_attribute *svc_chngd_ccc;
89 struct queue *profiles;
93 struct btd_gatt_database *database;
99 struct queue *profiles;
100 struct queue *services;
101 struct queue *proxies;
104 struct external_service {
105 struct gatt_app *app;
106 char *path; /* Path to GattService1 */
108 struct gatt_db_attribute *attrib;
114 struct external_profile {
115 struct gatt_app *app;
117 struct queue *profiles; /* btd_profile list */
120 struct external_chrc {
121 struct external_service *service;
129 struct io *notify_io;
130 struct gatt_db_attribute *attrib;
131 struct gatt_db_attribute *ccc;
132 struct queue *pending_reads;
133 struct queue *pending_writes;
134 unsigned int ntfy_cnt;
137 struct external_desc {
138 struct external_service *service;
142 struct gatt_db_attribute *attrib;
144 struct queue *pending_reads;
145 struct queue *pending_writes;
149 struct btd_device *device;
153 struct gatt_db_attribute *attrib;
154 struct queue *owner_queue;
158 struct device_state {
159 struct btd_gatt_database *db;
162 unsigned int disc_id;
163 struct queue *ccc_states;
166 typedef uint8_t (*btd_gatt_database_ccc_write_t) (struct bt_att *att,
169 typedef void (*btd_gatt_database_destroy_t) (void *data);
178 btd_gatt_database_ccc_write_t callback;
179 btd_gatt_database_destroy_t destroy;
188 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
189 static void conf_cb_tizen(void *user_data);
192 static void ccc_cb_free(void *data)
194 struct ccc_cb_data *ccc_cb = data;
197 ccc_cb->destroy(ccc_cb->user_data);
202 static bool ccc_cb_match_service(const void *data, const void *match_data)
204 const struct ccc_cb_data *ccc_cb = data;
205 const struct gatt_db_attribute *attrib = match_data;
208 if (!gatt_db_attribute_get_service_handles(attrib, &start, &end))
211 return ccc_cb->handle >= start && ccc_cb->handle <= end;
214 static bool ccc_cb_match_handle(const void *data, const void *match_data)
216 const struct ccc_cb_data *ccc_cb = data;
217 uint16_t handle = PTR_TO_UINT(match_data);
219 return ccc_cb->handle == handle;
222 static bool dev_state_match(const void *a, const void *b)
224 const struct device_state *dev_state = a;
225 const struct device_info *dev_info = b;
227 return bacmp(&dev_state->bdaddr, &dev_info->bdaddr) == 0 &&
228 dev_state->bdaddr_type == dev_info->bdaddr_type;
231 static struct device_state *
232 find_device_state(struct btd_gatt_database *database, bdaddr_t *bdaddr,
235 struct device_info dev_info;
237 memset(&dev_info, 0, sizeof(dev_info));
239 bacpy(&dev_info.bdaddr, bdaddr);
240 dev_info.bdaddr_type = bdaddr_type;
242 return queue_find(database->device_states, dev_state_match, &dev_info);
245 static bool ccc_state_match(const void *a, const void *b)
247 const struct ccc_state *ccc = a;
248 uint16_t handle = PTR_TO_UINT(b);
250 return ccc->handle == handle;
253 static struct ccc_state *find_ccc_state(struct device_state *dev_state,
256 return queue_find(dev_state->ccc_states, ccc_state_match,
257 UINT_TO_PTR(handle));
260 static struct device_state *device_state_create(struct btd_gatt_database *db,
264 struct device_state *dev_state;
265 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
266 char addr[18] = { 0 };
268 ba2str(bdaddr, addr);
269 DBG("create device_state for %s [%d]", addr, bdaddr_type);
272 dev_state = new0(struct device_state, 1);
274 dev_state->ccc_states = queue_new();
275 bacpy(&dev_state->bdaddr, bdaddr);
276 dev_state->bdaddr_type = bdaddr_type;
281 static void device_state_free(void *data)
283 struct device_state *state = data;
285 queue_destroy(state->ccc_states, free);
289 static void clear_ccc_state(void *data, void *user_data)
291 struct ccc_state *ccc = data;
292 struct btd_gatt_database *db = user_data;
293 struct ccc_cb_data *ccc_cb;
298 ccc_cb = queue_find(db->ccc_callbacks, ccc_cb_match_handle,
299 UINT_TO_PTR(ccc->handle));
303 if (ccc_cb->callback)
304 ccc_cb->callback(NULL, 0, ccc_cb->user_data);
307 static void att_disconnected(int err, void *user_data)
309 struct device_state *state = user_data;
310 struct btd_device *device;
316 device = btd_adapter_get_device(state->db->adapter, &state->bdaddr,
321 if (device_is_paired(device, state->bdaddr_type))
325 /* Remove device state if device no longer exists or is not paired */
326 if (queue_remove(state->db->device_states, state)) {
327 queue_foreach(state->ccc_states, clear_ccc_state, state->db);
328 device_state_free(state);
332 static bool get_dst_info(struct bt_att *att, bdaddr_t *dst, uint8_t *dst_type)
334 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
335 return bt_att_get_remote_addr(att, dst, dst_type);
337 GIOChannel *io = NULL;
340 io = g_io_channel_unix_new(bt_att_get_fd(att));
344 bt_io_get(io, &gerr, BT_IO_OPT_DEST_BDADDR, dst,
345 BT_IO_OPT_DEST_TYPE, dst_type,
348 error("gatt: bt_io_get: %s", gerr->message);
350 g_io_channel_unref(io);
354 g_io_channel_unref(io);
360 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
361 static void send_service_changed_indication_on_reconnect(
362 struct btd_device *device,
363 struct bt_gatt_server *server)
365 struct btd_gatt_database *database;
366 uint16_t start_handle = 0X0001, end_handle = 0xFFFF;
368 uint16_t svc_chngd_handle;
371 database = btd_adapter_get_database(device_get_adapter(device));
376 svc_chngd_handle = gatt_db_attribute_get_handle(database->svc_chngd_ccc);
378 put_le16(start_handle, value);
379 put_le16(end_handle, value + 2);
381 bt_gatt_server_send_indication(server, svc_chngd_handle,
382 value, sizeof(value), conf_cb_tizen,
386 static bool dev_addr_match(const void *a, const void *b)
388 const struct device_state *dev_state = a;
389 const struct device_info *dev_info = b;
391 if (bacmp(&dev_state->bdaddr, &dev_info->bdaddr) == 0)
397 static struct device_state *
398 find_device_state_from_address(struct btd_gatt_database *database, const bdaddr_t *bdaddr)
400 struct device_info dev_info;
402 memset(&dev_info, 0, sizeof(dev_info));
404 bacpy(&dev_info.bdaddr, bdaddr);
406 return queue_find(database->device_states, dev_addr_match, &dev_info);
410 static struct device_state *get_device_state(struct btd_gatt_database *database,
413 struct device_state *dev_state;
417 if (!get_dst_info(att, &bdaddr, &bdaddr_type))
421 * Find and return a device state. If a matching state doesn't exist,
422 * then create a new one.
424 dev_state = find_device_state(database, &bdaddr, bdaddr_type);
428 dev_state = device_state_create(database, &bdaddr, bdaddr_type);
430 queue_push_tail(database->device_states, dev_state);
433 if (!dev_state->disc_id)
434 dev_state->disc_id = bt_att_register_disconnect(att,
441 static struct ccc_state *get_ccc_state(struct btd_gatt_database *database,
442 struct bt_att *att, uint16_t handle)
444 struct device_state *dev_state;
445 struct ccc_state *ccc;
447 dev_state = get_device_state(database, att);
451 ccc = find_ccc_state(dev_state, handle);
455 ccc = new0(struct ccc_state, 1);
456 ccc->handle = handle;
457 queue_push_tail(dev_state->ccc_states, ccc);
462 static void cancel_pending_read(void *data)
464 struct pending_op *op = data;
466 gatt_db_attribute_read_result(op->attrib, op->id,
467 BT_ATT_ERROR_REQUEST_NOT_SUPPORTED,
469 op->owner_queue = NULL;
472 static void cancel_pending_write(void *data)
474 struct pending_op *op = data;
476 gatt_db_attribute_write_result(op->attrib, op->id,
477 BT_ATT_ERROR_REQUEST_NOT_SUPPORTED);
478 op->owner_queue = NULL;
481 static void chrc_free(void *data)
483 struct external_chrc *chrc = data;
485 io_destroy(chrc->write_io);
486 io_destroy(chrc->notify_io);
488 queue_destroy(chrc->pending_reads, cancel_pending_read);
489 queue_destroy(chrc->pending_writes, cancel_pending_write);
493 g_dbus_proxy_set_property_watch(chrc->proxy, NULL, NULL);
494 g_dbus_proxy_unref(chrc->proxy);
499 static void desc_free(void *data)
501 struct external_desc *desc = data;
503 queue_destroy(desc->pending_reads, cancel_pending_read);
504 queue_destroy(desc->pending_writes, cancel_pending_write);
506 g_dbus_proxy_unref(desc->proxy);
507 g_free(desc->chrc_path);
512 static void service_free(void *data)
514 struct external_service *service = data;
516 queue_destroy(service->chrcs, chrc_free);
517 queue_destroy(service->descs, desc_free);
520 gatt_db_remove_service(service->app->database->db,
523 if (service->app->client)
524 g_dbus_proxy_unref(service->proxy);
526 g_free(service->path);
531 static void profile_remove(void *data)
533 struct btd_profile *p = data;
535 DBG("Removed \"%s\"", p->name);
537 adapter_foreach(adapter_remove_profile, p);
538 btd_profile_unregister(p);
540 g_free((void *) p->name);
541 g_free((void *) p->remote_uuid);
546 static void profile_release(struct external_profile *profile)
548 DBG("Releasing \"%s\"", profile->app->owner);
550 g_dbus_proxy_method_call(profile->proxy, "Release", NULL, NULL, NULL,
554 static void profile_free(void *data)
556 struct external_profile *profile = data;
558 queue_destroy(profile->profiles, profile_remove);
560 profile_release(profile);
562 g_dbus_proxy_unref(profile->proxy);
567 static void app_free(void *data)
569 struct gatt_app *app = data;
571 queue_destroy(app->profiles, profile_free);
572 queue_destroy(app->services, service_free);
573 queue_destroy(app->proxies, NULL);
576 g_dbus_client_set_disconnect_watch(app->client, NULL, NULL);
577 g_dbus_client_set_proxy_handlers(app->client, NULL, NULL,
579 g_dbus_client_set_ready_watch(app->client, NULL, NULL);
580 g_dbus_client_unref(app->client);
584 dbus_message_unref(app->reg);
592 static void gatt_record_free(void *data)
594 struct gatt_record *rec = data;
596 adapter_service_remove(rec->database->adapter, rec->handle);
600 static void gatt_database_free(void *data)
602 struct btd_gatt_database *database = data;
604 if (database->le_io) {
605 g_io_channel_shutdown(database->le_io, FALSE, NULL);
606 g_io_channel_unref(database->le_io);
609 if (database->l2cap_io) {
610 g_io_channel_shutdown(database->l2cap_io, FALSE, NULL);
611 g_io_channel_unref(database->l2cap_io);
614 /* TODO: Persistently store CCC states before freeing them */
615 gatt_db_unregister(database->db, database->db_id);
617 queue_destroy(database->records, gatt_record_free);
618 queue_destroy(database->device_states, device_state_free);
619 queue_destroy(database->apps, app_free);
620 queue_destroy(database->profiles, profile_free);
621 queue_destroy(database->ccc_callbacks, ccc_cb_free);
622 database->device_states = NULL;
623 database->ccc_callbacks = NULL;
625 gatt_db_unref(database->db);
627 btd_adapter_unref(database->adapter);
631 static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
633 struct btd_adapter *adapter;
634 struct btd_device *device;
639 error("%s", gerr->message);
643 bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src,
644 BT_IO_OPT_DEST_BDADDR, &dst,
645 BT_IO_OPT_DEST_TYPE, &dst_type,
648 error("bt_io_get: %s", gerr->message);
653 DBG("New incoming %s ATT connection", dst_type == BDADDR_BREDR ?
656 adapter = adapter_find(&src);
660 device = btd_adapter_get_device(adapter, &dst, dst_type);
664 device_attach_att(device, io);
666 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
667 if (btd_device_get_svc_changed_indication(device)) {
668 send_service_changed_indication_on_reconnect(device,
669 btd_device_get_gatt_server(device));
674 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
675 #define LE_BEARER_POSTFIX " LE"
676 #define LE_BEARER_POSTFIX_LEN 3
678 static bool get_dst_info(struct bt_att *att, bdaddr_t *dst, uint8_t *dst_type);
681 static void gap_device_name_read_cb(struct gatt_db_attribute *attrib,
682 unsigned int id, uint16_t offset,
683 uint8_t opcode, struct bt_att *att,
686 struct btd_gatt_database *database = user_data;
689 const uint8_t *value = NULL;
690 const char *device_name;
691 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
692 bdaddr_t dst = { { 0 } };
693 uint8_t dst_type = 0;
694 char le_name[MAX_NAME_LENGTH + 1];
697 DBG("GAP Device Name read request\n");
699 device_name = btd_adapter_get_name(database->adapter);
700 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
701 if (get_dst_info(att, &dst, &dst_type) && dst_type != BDADDR_BREDR &&
702 bacmp(btd_adapter_get_address(database->adapter),
703 btd_adapter_get_le_address(database->adapter))) {
706 g_strlcpy(le_name, device_name,
707 sizeof(le_name) - LE_BEARER_POSTFIX_LEN);
708 if (!g_utf8_validate(le_name, -1, (const char **)&ptr))
711 g_strlcat(le_name, LE_BEARER_POSTFIX, sizeof(le_name));
712 DBG("Append LE bearer postfix : %s", le_name);
714 device_name = le_name;
717 len = strlen(device_name);
720 error = BT_ATT_ERROR_INVALID_OFFSET;
725 value = len ? (const uint8_t *) &device_name[offset] : NULL;
728 gatt_db_attribute_read_result(attrib, id, error, value, len);
731 static void gap_appearance_read_cb(struct gatt_db_attribute *attrib,
732 unsigned int id, uint16_t offset,
733 uint8_t opcode, struct bt_att *att,
736 struct btd_gatt_database *database = user_data;
739 const uint8_t *value = NULL;
740 uint8_t appearance[2];
743 DBG("GAP Appearance read request\n");
745 dev_class = btd_adapter_get_class(database->adapter);
748 error = BT_ATT_ERROR_INVALID_OFFSET;
752 appearance[0] = dev_class & 0x00ff;
753 appearance[1] = (dev_class >> 8) & 0x001f;
756 value = len ? &appearance[offset] : NULL;
759 gatt_db_attribute_read_result(attrib, id, error, value, len);
762 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
763 static void gap_rpa_res_support_read_cb(struct gatt_db_attribute *attrib,
764 unsigned int id, uint16_t offset,
765 uint8_t opcode, struct bt_att *att,
768 struct btd_gatt_database *database = user_data;
771 const uint8_t *value = NULL;
772 uint8_t rpa_res_support = 0x00;
774 rpa_res_support = btd_adapter_get_rpa_res_support_value(database->adapter);
777 error = BT_ATT_ERROR_INVALID_OFFSET;
782 value = len ? &rpa_res_support : NULL;
785 gatt_db_attribute_read_result(attrib, id, error, value, len);
789 static sdp_record_t *record_new(uuid_t *uuid, uint16_t start, uint16_t end)
791 sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
792 uuid_t root_uuid, proto_uuid, l2cap;
793 sdp_record_t *record;
794 sdp_data_t *psm, *sh, *eh;
795 uint16_t lp = ATT_PSM;
803 record = sdp_record_alloc();
807 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
808 root = sdp_list_append(NULL, &root_uuid);
809 sdp_set_browse_groups(record, root);
810 sdp_list_free(root, NULL);
812 svclass_id = sdp_list_append(NULL, uuid);
813 sdp_set_service_classes(record, svclass_id);
814 sdp_list_free(svclass_id, NULL);
816 sdp_uuid16_create(&l2cap, L2CAP_UUID);
817 proto[0] = sdp_list_append(NULL, &l2cap);
818 psm = sdp_data_alloc(SDP_UINT16, &lp);
819 proto[0] = sdp_list_append(proto[0], psm);
820 apseq = sdp_list_append(NULL, proto[0]);
822 sdp_uuid16_create(&proto_uuid, ATT_UUID);
823 proto[1] = sdp_list_append(NULL, &proto_uuid);
824 sh = sdp_data_alloc(SDP_UINT16, &start);
825 proto[1] = sdp_list_append(proto[1], sh);
826 eh = sdp_data_alloc(SDP_UINT16, &end);
827 proto[1] = sdp_list_append(proto[1], eh);
828 apseq = sdp_list_append(apseq, proto[1]);
830 aproto = sdp_list_append(NULL, apseq);
831 sdp_set_access_protos(record, aproto);
836 sdp_list_free(proto[0], NULL);
837 sdp_list_free(proto[1], NULL);
838 sdp_list_free(apseq, NULL);
839 sdp_list_free(aproto, NULL);
844 static void database_add_record(struct btd_gatt_database *database,
845 struct gatt_db_attribute *attr)
847 struct gatt_record *rec;
848 sdp_record_t *record;
850 uuid_t svc, gap_uuid;
852 const char *name = NULL;
853 char uuidstr[MAX_LEN_UUID_STR];
855 gatt_db_attribute_get_service_uuid(attr, &uuid);
859 name = bt_uuid16_to_str(uuid.value.u16);
860 sdp_uuid16_create(&svc, uuid.value.u16);
863 name = bt_uuid32_to_str(uuid.value.u32);
864 sdp_uuid32_create(&svc, uuid.value.u32);
867 bt_uuid_to_string(&uuid, uuidstr, sizeof(uuidstr));
868 name = bt_uuidstr_to_str(uuidstr);
869 sdp_uuid128_create(&svc, (void *) &uuid.value.u128);
875 gatt_db_attribute_get_service_handles(attr, &start, &end);
877 record = record_new(&svc, start, end);
882 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
883 sdp_set_info_attr(record, name, "Samsung", NULL);
885 sdp_set_info_attr(record, name, "BlueZ", NULL);
888 sdp_uuid16_create(&gap_uuid, UUID_GAP);
889 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
890 if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) {
891 sdp_set_url_attr(record, "http://www.bluez.org/",
892 "http://www.bluez.org/",
893 "http://www.bluez.org/");
897 if (adapter_service_add(database->adapter, record) < 0) {
898 sdp_record_free(record);
902 rec = new0(struct gatt_record, 1);
903 rec->database = database;
904 rec->handle = record->handle;
906 queue_push_tail(database->records, rec);
909 static void populate_gap_service(struct btd_gatt_database *database)
912 struct gatt_db_attribute *service;
914 /* Add the GAP service */
915 bt_uuid16_create(&uuid, UUID_GAP);
916 service = gatt_db_add_service(database->db, &uuid, true, 5);
919 * Device Name characteristic.
921 bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
922 gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
923 BT_GATT_CHRC_PROP_READ,
924 gap_device_name_read_cb,
928 * Device Appearance characteristic.
930 bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
931 gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
932 BT_GATT_CHRC_PROP_READ,
933 gap_appearance_read_cb,
936 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
937 /* Central address resolution characteristic */
938 bt_uuid16_create(&uuid, GATT_CHARAC_CENTRAL_RPA_RESOLUTION);
939 gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
940 BT_GATT_CHRC_PROP_READ,
941 gap_rpa_res_support_read_cb,
945 gatt_db_service_set_active(service, true);
948 static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
949 unsigned int id, uint16_t offset,
950 uint8_t opcode, struct bt_att *att,
953 struct btd_gatt_database *database = user_data;
954 struct ccc_state *ccc;
957 const uint8_t *value = NULL;
960 handle = gatt_db_attribute_get_handle(attrib);
962 DBG("CCC read called for handle: 0x%04x", handle);
965 ecode = BT_ATT_ERROR_INVALID_OFFSET;
969 ccc = get_ccc_state(database, att, handle);
971 ecode = BT_ATT_ERROR_UNLIKELY;
976 value = len ? &ccc->value[offset] : NULL;
979 gatt_db_attribute_read_result(attrib, id, ecode, value, len);
982 static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib,
983 unsigned int id, uint16_t offset,
984 const uint8_t *value, size_t len,
985 uint8_t opcode, struct bt_att *att,
988 struct btd_gatt_database *database = user_data;
989 struct ccc_state *ccc;
990 struct ccc_cb_data *ccc_cb;
994 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
999 handle = gatt_db_attribute_get_handle(attrib);
1001 DBG("CCC write called for handle: 0x%04x", handle);
1003 if (!value || len != 2) {
1004 ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
1009 ecode = BT_ATT_ERROR_INVALID_OFFSET;
1013 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1014 if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
1015 ecode = BT_ATT_ERROR_UNLIKELY;
1020 ccc = get_ccc_state(database, att, handle);
1022 ecode = BT_ATT_ERROR_UNLIKELY;
1026 ccc_cb = queue_find(database->ccc_callbacks, ccc_cb_match_handle,
1027 UINT_TO_PTR(gatt_db_attribute_get_handle(attrib)));
1029 ecode = BT_ATT_ERROR_UNLIKELY;
1033 /* If value is identical, then just succeed */
1034 if (ccc->value[0] == value[0] && ccc->value[1] == value[1])
1037 if (ccc_cb->callback)
1038 ecode = ccc_cb->callback(att, get_le16(value),
1042 ccc->value[0] = value[0];
1043 ccc->value[1] = value[1];
1047 gatt_db_attribute_write_result(attrib, id, ecode);
1048 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1050 uint16_t svc_chngd_handle = gatt_db_attribute_get_handle(database->svc_chngd_ccc);
1051 if (handle == svc_chngd_handle) {
1052 if (ccc->value[0] != 0) {
1053 struct btd_device *device = NULL;
1054 device = btd_adapter_get_device(
1056 &bdaddr, bdaddr_type);
1060 btd_device_set_svc_changed_indication(device, true);
1067 static struct gatt_db_attribute *
1068 service_add_ccc(struct gatt_db_attribute *service,
1069 struct btd_gatt_database *database,
1070 btd_gatt_database_ccc_write_t write_callback,
1072 btd_gatt_database_destroy_t destroy)
1074 struct gatt_db_attribute *ccc;
1075 struct ccc_cb_data *ccc_cb;
1078 ccc_cb = new0(struct ccc_cb_data, 1);
1080 bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
1081 ccc = gatt_db_service_add_descriptor(service, &uuid,
1082 BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
1083 gatt_ccc_read_cb, gatt_ccc_write_cb, database);
1085 error("Failed to create CCC entry in database");
1090 ccc_cb->handle = gatt_db_attribute_get_handle(ccc);
1091 ccc_cb->callback = write_callback;
1092 ccc_cb->destroy = destroy;
1093 ccc_cb->user_data = user_data;
1095 queue_push_tail(database->ccc_callbacks, ccc_cb);
1100 static void populate_gatt_service(struct btd_gatt_database *database)
1103 struct gatt_db_attribute *service;
1105 /* Add the GATT service */
1106 bt_uuid16_create(&uuid, UUID_GATT);
1107 service = gatt_db_add_service(database->db, &uuid, true, 4);
1109 bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
1110 database->svc_chngd = gatt_db_service_add_characteristic(service, &uuid,
1111 BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_INDICATE,
1112 NULL, NULL, database);
1114 database->svc_chngd_ccc = service_add_ccc(service, database, NULL, NULL,
1117 gatt_db_service_set_active(service, true);
1120 static void register_core_services(struct btd_gatt_database *database)
1122 populate_gap_service(database);
1123 populate_gatt_service(database);
1127 struct btd_gatt_database *database;
1128 uint16_t handle, ccc_handle;
1129 const uint8_t *value;
1135 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1136 struct notify_indicate {
1137 struct btd_gatt_database *database;
1139 uint16_t handle, ccc_handle;
1140 const uint8_t *value;
1145 struct notify_indicate_cb {
1147 struct btd_device *device;
1150 static void indicate_confirm_free(void *data)
1152 struct notify_indicate_cb *indicate = data;
1158 static void indicate_confirm_setup_cb(DBusMessageIter *iter, void *user_data)
1160 struct btd_device *device = user_data;
1161 char dst_addr[18] = { 0 };
1162 char *addr_value = dst_addr;
1163 gboolean complete = FALSE;
1165 if (device_get_rpa_exist(device) == true) {
1166 ba2str(device_get_rpa(device), dst_addr);
1168 ba2str(device_get_address(device), dst_addr);
1171 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &addr_value);
1174 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &complete);
1177 static void indicate_confirm_reply_cb(DBusMessage *message, void *user_data)
1181 dbus_error_init(&error);
1183 if (dbus_set_error_from_message(&error, message) == TRUE) {
1184 DBG("Failed to send indication/notification");
1185 dbus_error_free(&error);
1191 static void conf_cb(void *user_data)
1193 GDBusProxy *proxy = user_data;
1194 DBG("GATT server received confirmation");
1197 g_dbus_proxy_method_call(proxy, "Confirm", NULL, NULL, NULL, NULL);
1201 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1202 static void conf_cb_tizen(void *user_data)
1205 DBG("GATT server received indication confirmation");
1206 struct notify_indicate_cb *confirm = user_data;
1209 /* Send confirmation to application */
1210 if (g_dbus_proxy_method_call(confirm->proxy, "IndicateConfirm",
1211 indicate_confirm_setup_cb,
1212 indicate_confirm_reply_cb, confirm->device,
1214 error("g_dbus_proxy_method_call for \"IndicateConfirm\" failed");
1216 g_dbus_proxy_unref(confirm->proxy);
1217 confirm->proxy = NULL;
1223 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1224 static void send_notification_indication_to_device(void *data, void *user_data)
1226 struct device_state *device_state = data;
1227 struct notify_indicate *notify_indicate = user_data;
1228 struct ccc_state *ccc;
1229 struct btd_device *device;
1230 struct notify_indicate_cb *confirm;
1232 ccc = find_ccc_state(device_state, notify_indicate->ccc_handle);
1236 if (!ccc->value[0] || (notify_indicate->indicate && !(ccc->value[0] & 0x02)))
1239 device = btd_adapter_get_device(notify_indicate->database->adapter,
1240 &device_state->bdaddr,
1241 device_state->bdaddr_type);
1245 confirm = new0(struct notify_indicate_cb, 1);
1246 confirm->proxy = g_dbus_proxy_ref(notify_indicate->proxy);
1247 confirm->device = device;
1249 * TODO: If the device is not connected but bonded, send the
1250 * notification/indication when it becomes connected.
1252 if (!notify_indicate->indicate) {
1253 DBG("GATT server sending notification");
1254 bt_gatt_server_send_notification(
1255 btd_device_get_gatt_server(device),
1256 notify_indicate->handle, notify_indicate->value,
1257 notify_indicate->len);
1258 /* In case of Notification, send response to application
1259 * as remote device do not respond for notification */
1260 conf_cb_tizen(confirm);
1261 indicate_confirm_free((void *)confirm);
1265 DBG("GATT server sending indication");
1267 bt_gatt_server_send_indication(btd_device_get_gatt_server(device),
1268 notify_indicate->handle,
1269 notify_indicate->value,
1270 notify_indicate->len, conf_cb_tizen,
1271 confirm, indicate_confirm_free);
1274 static void send_notification_indication_to_devices(GDBusProxy *proxy,
1275 struct btd_gatt_database *database,
1276 uint16_t handle, const uint8_t *value,
1277 uint16_t len, uint16_t ccc_handle,
1280 struct notify_indicate notify_indicate;
1282 DBG("notify for handle: 0x%04x", handle);
1284 memset(¬ify_indicate, 0, sizeof(notify_indicate));
1286 notify_indicate.database = database;
1287 notify_indicate.proxy = proxy;
1288 notify_indicate.handle = handle;
1289 notify_indicate.ccc_handle = ccc_handle;
1290 notify_indicate.value = value;
1291 notify_indicate.len = len;
1292 notify_indicate.indicate = indicate;
1294 queue_foreach(database->device_states, send_notification_indication_to_device,
1298 static void send_unicast_notification_indication_to_device(GDBusProxy *proxy,
1299 struct btd_gatt_database *database,
1300 uint16_t handle, const uint8_t *value,
1301 uint16_t len, uint16_t ccc_handle,
1302 bool indicate, const bdaddr_t *unicast_addr)
1304 struct device_state *dev_state;
1305 struct notify_indicate notify_indicate;
1307 DBG("notify for handle: 0x%04x", handle);
1309 memset(¬ify_indicate, 0, sizeof(notify_indicate));
1311 notify_indicate.database = database;
1312 notify_indicate.proxy = proxy;
1313 notify_indicate.handle = handle;
1314 notify_indicate.ccc_handle = ccc_handle;
1315 notify_indicate.value = value;
1316 notify_indicate.len = len;
1317 notify_indicate.indicate = indicate;
1319 /* Find and return a device state. */
1320 dev_state = find_device_state_from_address(database, unicast_addr);
1323 send_notification_indication_to_device(dev_state, ¬ify_indicate);
1327 static void send_notification_to_device(void *data, void *user_data)
1329 struct device_state *device_state = data;
1330 struct notify *notify = user_data;
1331 struct ccc_state *ccc;
1332 struct btd_device *device;
1333 struct bt_gatt_server *server;
1335 ccc = find_ccc_state(device_state, notify->ccc_handle);
1339 if (!ccc->value[0] || (notify->indicate && !(ccc->value[0] & 0x02)))
1342 device = btd_adapter_get_device(notify->database->adapter,
1343 &device_state->bdaddr,
1344 device_state->bdaddr_type);
1348 server = btd_device_get_gatt_server(device);
1350 if (!device_is_paired(device, device_state->bdaddr_type))
1356 * TODO: If the device is not connected but bonded, send the
1357 * notification/indication when it becomes connected.
1359 if (!notify->indicate) {
1360 DBG("GATT server sending notification");
1361 bt_gatt_server_send_notification(server,
1362 notify->handle, notify->value,
1367 DBG("GATT server sending indication");
1368 bt_gatt_server_send_indication(server, notify->handle, notify->value,
1369 notify->len, conf_cb,
1370 notify->proxy, NULL);
1375 /* Remove device state if device no longer exists or is not paired */
1376 if (queue_remove(notify->database->device_states, device_state)) {
1377 queue_foreach(device_state->ccc_states, clear_ccc_state,
1379 device_state_free(device_state);
1383 static void send_notification_to_devices(struct btd_gatt_database *database,
1384 uint16_t handle, const uint8_t *value,
1385 uint16_t len, uint16_t ccc_handle,
1386 bool indicate, GDBusProxy *proxy)
1388 struct notify notify;
1390 memset(¬ify, 0, sizeof(notify));
1392 notify.database = database;
1393 notify.handle = handle;
1394 notify.ccc_handle = ccc_handle;
1395 notify.value = value;
1397 notify.indicate = indicate;
1398 notify.proxy = proxy;
1400 queue_foreach(database->device_states, send_notification_to_device,
1404 static void send_service_changed(struct btd_gatt_database *database,
1405 struct gatt_db_attribute *attrib)
1407 uint16_t start, end;
1409 uint16_t handle, ccc_handle;
1411 if (!gatt_db_attribute_get_service_handles(attrib, &start, &end)) {
1412 error("Failed to obtain changed service handles");
1416 handle = gatt_db_attribute_get_handle(database->svc_chngd);
1417 ccc_handle = gatt_db_attribute_get_handle(database->svc_chngd_ccc);
1419 if (!handle || !ccc_handle) {
1420 error("Failed to obtain handles for \"Service Changed\""
1425 put_le16(start, value);
1426 put_le16(end, value + 2);
1428 send_notification_to_devices(database, handle, value, sizeof(value),
1429 ccc_handle, true, NULL);
1432 static void gatt_db_service_added(struct gatt_db_attribute *attrib,
1435 struct btd_gatt_database *database = user_data;
1437 DBG("GATT Service added to local database");
1439 database_add_record(database, attrib);
1441 send_service_changed(database, attrib);
1444 static bool ccc_match_service(const void *data, const void *match_data)
1446 const struct ccc_state *ccc = data;
1447 const struct gatt_db_attribute *attrib = match_data;
1448 uint16_t start, end;
1450 if (!gatt_db_attribute_get_service_handles(attrib, &start, &end))
1453 return ccc->handle >= start && ccc->handle <= end;
1456 static void remove_device_ccc(void *data, void *user_data)
1458 struct device_state *state = data;
1460 queue_remove_all(state->ccc_states, ccc_match_service, user_data, free);
1463 static bool match_gatt_record(const void *data, const void *user_data)
1465 const struct gatt_record *rec = data;
1466 const struct gatt_db_attribute *attr = user_data;
1468 return (rec->attr == attr);
1471 static void gatt_db_service_removed(struct gatt_db_attribute *attrib,
1474 struct btd_gatt_database *database = user_data;
1475 struct gatt_record *rec;
1477 DBG("Local GATT service removed");
1479 rec = queue_remove_if(database->records, match_gatt_record, attrib);
1481 gatt_record_free(rec);
1483 send_service_changed(database, attrib);
1485 queue_foreach(database->device_states, remove_device_ccc, attrib);
1486 queue_remove_all(database->ccc_callbacks, ccc_cb_match_service, attrib,
1490 struct svc_match_data {
1495 static bool match_app(const void *a, const void *b)
1497 const struct gatt_app *app = a;
1498 const struct svc_match_data *data = b;
1500 return g_strcmp0(app->path, data->path) == 0 &&
1501 g_strcmp0(app->owner, data->sender) == 0;
1504 static gboolean app_free_idle_cb(void *data)
1511 static void client_disconnect_cb(DBusConnection *conn, void *user_data)
1513 struct gatt_app *app = user_data;
1514 struct btd_gatt_database *database = app->database;
1516 DBG("Client disconnected");
1518 if (queue_remove(database->apps, app))
1522 static void remove_app(void *data)
1524 struct gatt_app *app = data;
1527 * Set callback to NULL to avoid potential race condition
1528 * when calling remove_app and GDBusClient unref.
1530 g_dbus_client_set_disconnect_watch(app->client, NULL, NULL);
1533 * Set proxy handlers to NULL, so that this gets called only once when
1534 * the first proxy that belongs to this service gets removed.
1536 g_dbus_client_set_proxy_handlers(app->client, NULL, NULL, NULL, NULL);
1539 queue_remove(app->database->apps, app);
1542 * Do not run in the same loop, this may be a disconnect
1543 * watch call and GDBusClient should not be destroyed.
1545 g_idle_add(app_free_idle_cb, app);
1548 static bool match_service_by_path(const void *a, const void *b)
1550 const struct external_service *service = a;
1551 const char *path = b;
1553 return strcmp(service->path, path) == 0;
1556 static bool parse_path(GDBusProxy *proxy, const char *name, const char **path)
1558 DBusMessageIter iter;
1560 if (!g_dbus_proxy_get_property(proxy, name, &iter))
1563 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
1566 dbus_message_iter_get_basic(&iter, path);
1571 static bool incr_attr_count(struct external_service *service, uint16_t incr)
1573 if (service->attr_cnt > UINT16_MAX - incr)
1576 service->attr_cnt += incr;
1581 static bool parse_chrc_flags(DBusMessageIter *array, uint8_t *props,
1582 uint8_t *ext_props, uint32_t *perm)
1586 *props = *ext_props = 0;
1589 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_STRING)
1592 dbus_message_iter_get_basic(array, &flag);
1594 if (!strcmp("broadcast", flag))
1595 *props |= BT_GATT_CHRC_PROP_BROADCAST;
1596 else if (!strcmp("read", flag)) {
1597 *props |= BT_GATT_CHRC_PROP_READ;
1598 *perm |= BT_ATT_PERM_READ;
1599 } else if (!strcmp("write-without-response", flag)) {
1600 *props |= BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP;
1601 *perm |= BT_ATT_PERM_WRITE;
1602 } else if (!strcmp("write", flag)) {
1603 *props |= BT_GATT_CHRC_PROP_WRITE;
1604 *perm |= BT_ATT_PERM_WRITE;
1605 } else if (!strcmp("notify", flag)) {
1606 *props |= BT_GATT_CHRC_PROP_NOTIFY;
1607 } else if (!strcmp("indicate", flag)) {
1608 *props |= BT_GATT_CHRC_PROP_INDICATE;
1609 } else if (!strcmp("authenticated-signed-writes", flag)) {
1610 *props |= BT_GATT_CHRC_PROP_AUTH;
1611 *perm |= BT_ATT_PERM_WRITE;
1612 } else if (!strcmp("reliable-write", flag)) {
1613 *ext_props |= BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE;
1614 *perm |= BT_ATT_PERM_WRITE;
1615 } else if (!strcmp("writable-auxiliaries", flag)) {
1616 *ext_props |= BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX;
1617 } else if (!strcmp("encrypt-read", flag)) {
1618 *props |= BT_GATT_CHRC_PROP_READ;
1619 *ext_props |= BT_GATT_CHRC_EXT_PROP_ENC_READ;
1620 *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_ENCRYPT;
1621 } else if (!strcmp("encrypt-write", flag)) {
1622 *props |= BT_GATT_CHRC_PROP_WRITE;
1623 *ext_props |= BT_GATT_CHRC_EXT_PROP_ENC_WRITE;
1624 *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_ENCRYPT;
1625 } else if (!strcmp("encrypt-authenticated-read", flag)) {
1626 *props |= BT_GATT_CHRC_PROP_READ;
1627 *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_READ;
1628 *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN;
1629 } else if (!strcmp("encrypt-authenticated-write", flag)) {
1630 *props |= BT_GATT_CHRC_PROP_WRITE;
1631 *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_WRITE;
1632 *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN;
1633 } else if (!strcmp("secure-read", flag)) {
1634 *props |= BT_GATT_CHRC_PROP_READ;
1635 *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_READ;
1636 *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_SECURE;
1637 } else if (!strcmp("secure-write", flag)) {
1638 *props |= BT_GATT_CHRC_PROP_WRITE;
1639 *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_WRITE;
1640 *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_SECURE;
1642 error("Invalid characteristic flag: %s", flag);
1645 } while (dbus_message_iter_next(array));
1648 *props |= BT_GATT_CHRC_PROP_EXT_PROP;
1653 static bool parse_desc_flags(DBusMessageIter *array, uint32_t *perm)
1660 if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_STRING)
1663 dbus_message_iter_get_basic(array, &flag);
1665 if (!strcmp("read", flag))
1666 *perm |= BT_ATT_PERM_READ;
1667 else if (!strcmp("write", flag))
1668 *perm |= BT_ATT_PERM_WRITE;
1669 else if (!strcmp("encrypt-read", flag))
1670 *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_ENCRYPT;
1671 else if (!strcmp("encrypt-write", flag))
1672 *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_ENCRYPT;
1673 else if (!strcmp("encrypt-authenticated-read", flag))
1674 *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN;
1675 else if (!strcmp("encrypt-authenticated-write", flag))
1676 *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN;
1677 else if (!strcmp("secure-read", flag))
1678 *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_SECURE;
1679 else if (!strcmp("secure-write", flag))
1680 *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_SECURE;
1682 error("Invalid descriptor flag: %s", flag);
1685 } while (dbus_message_iter_next(array));
1690 static bool parse_flags(GDBusProxy *proxy, uint8_t *props, uint8_t *ext_props,
1693 DBusMessageIter iter, array;
1696 if (!g_dbus_proxy_get_property(proxy, "Flags", &iter))
1699 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
1702 dbus_message_iter_recurse(&iter, &array);
1704 iface = g_dbus_proxy_get_interface(proxy);
1705 if (!strcmp(iface, GATT_DESC_IFACE))
1706 return parse_desc_flags(&array, perm);
1708 return parse_chrc_flags(&array, props, ext_props, perm);
1711 static struct external_chrc *chrc_create(struct gatt_app *app,
1715 struct external_service *service;
1716 struct external_chrc *chrc;
1717 const char *service_path;
1719 if (!parse_path(proxy, "Service", &service_path)) {
1720 error("Failed to obtain service path for characteristic");
1724 service = queue_find(app->services, match_service_by_path,
1727 error("Unable to find service for characteristic: %s", path);
1731 chrc = new0(struct external_chrc, 1);
1732 chrc->pending_reads = queue_new();
1733 chrc->pending_writes = queue_new();
1735 chrc->path = g_strdup(path);
1739 chrc->service = service;
1740 chrc->proxy = g_dbus_proxy_ref(proxy);
1743 * Add 2 for the characteristic declaration and the value
1746 if (!incr_attr_count(chrc->service, 2)) {
1747 error("Failed to increment attribute count");
1752 * Parse characteristic flags (i.e. properties) here since they
1753 * are used to determine if any special descriptors should be
1756 if (!parse_flags(proxy, &chrc->props, &chrc->ext_props, &chrc->perm)) {
1757 error("Failed to parse characteristic properties");
1761 if ((chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
1762 chrc->props & BT_GATT_CHRC_PROP_INDICATE) &&
1763 !incr_attr_count(chrc->service, 1)) {
1764 error("Failed to increment attribute count for CCC");
1768 if (chrc->ext_props && !incr_attr_count(chrc->service, 1)) {
1769 error("Failed to increment attribute count for CEP");
1773 queue_push_tail(chrc->service->chrcs, chrc);
1782 static bool match_chrc(const void *a, const void *b)
1784 const struct external_chrc *chrc = a;
1785 const char *path = b;
1787 return strcmp(chrc->path, path) == 0;
1790 static bool match_service_by_chrc(const void *a, const void *b)
1792 const struct external_service *service = a;
1793 const char *path = b;
1795 return queue_find(service->chrcs, match_chrc, path);
1798 static struct external_desc *desc_create(struct gatt_app *app,
1801 struct external_service *service;
1802 struct external_desc *desc;
1803 const char *chrc_path;
1805 if (!parse_path(proxy, "Characteristic", &chrc_path)) {
1806 error("Failed to obtain characteristic path for descriptor");
1810 service = queue_find(app->services, match_service_by_chrc, chrc_path);
1812 error("Unable to find service for characteristic: %s",
1817 desc = new0(struct external_desc, 1);
1818 desc->pending_reads = queue_new();
1819 desc->pending_writes = queue_new();
1821 desc->chrc_path = g_strdup(chrc_path);
1822 if (!desc->chrc_path)
1825 desc->service = service;
1826 desc->proxy = g_dbus_proxy_ref(proxy);
1828 /* Add 1 for the descriptor attribute */
1829 if (!incr_attr_count(desc->service, 1)) {
1830 error("Failed to increment attribute count");
1835 * Parse descriptors flags here since they are used to
1836 * determine the permission the descriptor should have
1838 if (!parse_flags(proxy, NULL, NULL, &desc->perm)) {
1839 error("Failed to parse characteristic properties");
1843 queue_push_tail(desc->service->descs, desc);
1852 static bool check_service_path(GDBusProxy *proxy,
1853 struct external_service *service)
1855 const char *service_path;
1857 if (!parse_path(proxy, "Service", &service_path))
1860 return g_strcmp0(service_path, service->path) == 0;
1863 static struct external_service *create_service(struct gatt_app *app,
1867 struct external_service *service;
1869 if (!path || !g_str_has_prefix(path, "/"))
1872 service = queue_find(app->services, match_service_by_path, path);
1874 error("Duplicated service: %s", path);
1878 service = new0(struct external_service, 1);
1882 service->path = g_strdup(path);
1886 service->proxy = g_dbus_proxy_ref(proxy);
1887 service->chrcs = queue_new();
1888 service->descs = queue_new();
1890 /* Add 1 for the service declaration */
1891 if (!incr_attr_count(service, 1)) {
1892 error("Failed to increment attribute count");
1896 queue_push_tail(app->services, service);
1901 service_free(service);
1905 static void proxy_added_cb(GDBusProxy *proxy, void *user_data)
1907 struct gatt_app *app = user_data;
1908 const char *iface, *path;
1913 queue_push_tail(app->proxies, proxy);
1915 iface = g_dbus_proxy_get_interface(proxy);
1916 path = g_dbus_proxy_get_path(proxy);
1918 DBG("Object received: %s, iface: %s", path, iface);
1921 static void proxy_removed_cb(GDBusProxy *proxy, void *user_data)
1923 struct gatt_app *app = user_data;
1924 struct external_service *service;
1927 path = g_dbus_proxy_get_path(proxy);
1929 service = queue_remove_if(app->services, match_service_by_path,
1934 DBG("Proxy removed - removing service: %s", service->path);
1936 service_free(service);
1939 static bool parse_uuid(GDBusProxy *proxy, bt_uuid_t *uuid)
1941 DBusMessageIter iter;
1943 const char *uuidstr;
1945 if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
1948 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1951 dbus_message_iter_get_basic(&iter, &uuidstr);
1953 if (bt_string_to_uuid(uuid, uuidstr) < 0)
1956 /* GAP & GATT services are created and managed by BlueZ */
1957 bt_uuid16_create(&tmp, UUID_GAP);
1958 if (!bt_uuid_cmp(&tmp, uuid)) {
1959 error("GAP service must be handled by BlueZ");
1963 bt_uuid16_create(&tmp, UUID_GATT);
1964 if (!bt_uuid_cmp(&tmp, uuid)) {
1965 error("GATT service must be handled by BlueZ");
1972 static bool parse_primary(GDBusProxy *proxy, bool *primary)
1974 DBusMessageIter iter;
1977 if (!g_dbus_proxy_get_property(proxy, "Primary", &iter))
1980 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
1983 dbus_message_iter_get_basic(&iter, &val);
1990 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1991 static uint8_t dbus_error_to_att_ecode(const char *error_message)
1993 uint8_t att_ecode = 0;
1997 str = g_strrstr(error_message, "ATT error: 0x");
2000 att_ecode = g_ascii_xdigit_value(str[len - 2]) << 4;
2001 att_ecode += g_ascii_xdigit_value(str[len - 1]);
2003 att_ecode = BT_ATT_ERROR_UNLIKELY;
2008 static uint8_t dbus_error_to_att_ecode(const char *error_name)
2011 if (strcmp(error_name, "org.bluez.Error.Failed") == 0)
2012 return 0x80; /* For now return this "application error" */
2014 if (strcmp(error_name, "org.bluez.Error.NotSupported") == 0)
2015 return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
2017 if (strcmp(error_name, "org.bluez.Error.NotAuthorized") == 0)
2018 return BT_ATT_ERROR_AUTHORIZATION;
2020 if (strcmp(error_name, "org.bluez.Error.InvalidValueLength") == 0)
2021 return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
2023 if (strcmp(error_name, "org.bluez.Error.InProgress") == 0)
2024 return BT_ERROR_ALREADY_IN_PROGRESS;
2030 static void read_reply_cb(DBusMessage *message, void *user_data)
2032 struct pending_op *op = user_data;
2034 DBusMessageIter iter, array;
2036 uint8_t *value = NULL;
2039 if (!op->owner_queue) {
2040 DBG("Pending read was canceled when object got removed");
2044 dbus_error_init(&err);
2046 if (dbus_set_error_from_message(&err, message) == TRUE) {
2047 DBG("Failed to read value: %s: %s", err.name, err.message);
2048 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2049 ecode = dbus_error_to_att_ecode(err.message);
2051 ecode = dbus_error_to_att_ecode(err.name);
2052 ecode = ecode ? ecode : BT_ATT_ERROR_READ_NOT_PERMITTED;
2054 dbus_error_free(&err);
2058 dbus_message_iter_init(message, &iter);
2060 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
2062 * Return not supported for this, as the external app basically
2063 * doesn't properly support reading from this characteristic.
2065 ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
2066 error("Invalid return value received for \"ReadValue\"");
2070 dbus_message_iter_recurse(&iter, &array);
2071 dbus_message_iter_get_fixed_array(&array, &value, &len);
2074 ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
2080 /* Truncate the value if it's too large */
2081 len = MIN(BT_ATT_MAX_VALUE_LEN, len);
2082 value = len ? value : NULL;
2085 gatt_db_attribute_read_result(op->attrib, op->id, ecode, value, len);
2088 static void pending_op_free(void *data)
2090 struct pending_op *op = data;
2092 if (op->owner_queue)
2093 queue_remove(op->owner_queue, op);
2097 static struct pending_op *pending_read_new(struct btd_device *device,
2098 struct queue *owner_queue,
2099 struct gatt_db_attribute *attrib,
2100 unsigned int id, uint16_t offset,
2103 struct pending_op *op;
2105 op = new0(struct pending_op, 1);
2107 op->owner_queue = owner_queue;
2108 op->device = device;
2109 op->attrib = attrib;
2111 op->offset = offset;
2112 op->link_type = link_type;
2113 queue_push_tail(owner_queue, op);
2118 static void append_options(DBusMessageIter *iter, void *user_data)
2120 struct pending_op *op = user_data;
2121 const char *path = device_get_path(op->device);
2124 switch (op->link_type) {
2125 case BT_ATT_LINK_BREDR:
2128 case BT_ATT_LINK_LE:
2136 dict_append_entry(iter, "device", DBUS_TYPE_OBJECT_PATH, &path);
2138 dict_append_entry(iter, "offset", DBUS_TYPE_UINT16,
2141 dict_append_entry(iter, "link", DBUS_TYPE_STRING, &link);
2144 static void read_setup_cb(DBusMessageIter *iter, void *user_data)
2146 struct pending_op *op = user_data;
2147 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2148 char dst_addr[18] = { 0 };
2149 char *addr_value = dst_addr;
2151 if (device_get_rpa_exist(op->device) == true) {
2152 ba2str(device_get_rpa(op->device), dst_addr);
2154 ba2str(device_get_address(op->device), dst_addr);
2157 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &addr_value);
2158 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &op->id);
2159 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &op->offset);
2161 DBusMessageIter dict;
2163 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
2164 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
2165 DBUS_TYPE_STRING_AS_STRING
2166 DBUS_TYPE_VARIANT_AS_STRING
2167 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
2170 append_options(&dict, op);
2172 dbus_message_iter_close_container(iter, &dict);
2176 static struct pending_op *send_read(struct btd_device *device,
2177 struct gatt_db_attribute *attrib,
2179 struct queue *owner_queue,
2184 struct pending_op *op;
2186 op = pending_read_new(device, owner_queue, attrib, id, offset,
2189 if (g_dbus_proxy_method_call(proxy, "ReadValue", read_setup_cb,
2190 read_reply_cb, op, pending_op_free) == TRUE)
2193 pending_op_free(op);
2198 static void write_setup_cb(DBusMessageIter *iter, void *user_data)
2200 struct pending_op *op = user_data;
2201 DBusMessageIter array;
2203 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2204 char dst_addr[18] = { 0 };
2205 char *addr_value = dst_addr;
2206 gboolean response_needed = TRUE;
2208 if (device_get_rpa_exist(op->device) == true) {
2209 ba2str(device_get_rpa(op->device), dst_addr);
2211 ba2str(device_get_address(op->device), dst_addr);
2214 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &addr_value);
2215 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &op->id);
2216 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &op->offset);
2217 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &response_needed);
2220 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
2221 dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
2222 &op->data.iov_base, op->data.iov_len);
2223 dbus_message_iter_close_container(iter, &array);
2225 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
2227 DBusMessageIter dict;
2228 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
2229 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
2230 DBUS_TYPE_STRING_AS_STRING
2231 DBUS_TYPE_VARIANT_AS_STRING
2232 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
2235 append_options(&dict, op);
2237 dbus_message_iter_close_container(iter, &dict);
2241 if (!op->owner_queue) {
2242 gatt_db_attribute_write_result(op->attrib, op->id, 0);
2243 pending_op_free(op);
2247 static void write_reply_cb(DBusMessage *message, void *user_data)
2249 struct pending_op *op = user_data;
2251 DBusMessageIter iter;
2254 if (!op->owner_queue) {
2255 DBG("Pending write was canceled when object got removed");
2259 dbus_error_init(&err);
2261 if (dbus_set_error_from_message(&err, message) == TRUE) {
2262 DBG("Failed to write value: %s: %s", err.name, err.message);
2263 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2264 ecode = dbus_error_to_att_ecode(err.message);
2266 ecode = dbus_error_to_att_ecode(err.name);
2267 ecode = ecode ? ecode : BT_ATT_ERROR_WRITE_NOT_PERMITTED;
2269 dbus_error_free(&err);
2273 dbus_message_iter_init(message, &iter);
2274 if (dbus_message_iter_has_next(&iter)) {
2276 * Return not supported for this, as the external app basically
2277 * doesn't properly support the "WriteValue" API.
2279 ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
2280 error("Invalid return value received for \"WriteValue\"");
2284 gatt_db_attribute_write_result(op->attrib, op->id, ecode);
2287 static struct pending_op *pending_write_new(struct btd_device *device,
2288 struct queue *owner_queue,
2289 struct gatt_db_attribute *attrib,
2291 const uint8_t *value,
2293 uint16_t offset, uint8_t link_type)
2295 struct pending_op *op;
2297 op = new0(struct pending_op, 1);
2299 op->data.iov_base = (uint8_t *) value;
2300 op->data.iov_len = len;
2302 op->device = device;
2303 op->owner_queue = owner_queue;
2304 op->attrib = attrib;
2306 op->offset = offset;
2307 op->link_type = link_type;
2308 queue_push_tail(owner_queue, op);
2313 static struct pending_op *send_write(struct btd_device *device,
2314 struct gatt_db_attribute *attrib,
2316 struct queue *owner_queue,
2318 const uint8_t *value, size_t len,
2319 uint16_t offset, uint8_t link_type)
2321 struct pending_op *op;
2323 op = pending_write_new(device, owner_queue, attrib, id, value, len,
2326 if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup_cb,
2327 owner_queue ? write_reply_cb : NULL,
2328 op, pending_op_free) == TRUE)
2331 pending_op_free(op);
2336 static bool sock_hup(struct io *io, void *user_data)
2338 struct external_chrc *chrc = user_data;
2340 DBG("%p closed\n", io);
2342 if (io == chrc->write_io)
2343 chrc->write_io = NULL;
2345 chrc->notify_io = NULL;
2352 static bool sock_io_read(struct io *io, void *user_data)
2354 struct external_chrc *chrc = user_data;
2356 int fd = io_get_fd(io);
2359 bytes_read = read(fd, buf, sizeof(buf));
2363 send_notification_to_devices(chrc->service->app->database,
2364 gatt_db_attribute_get_handle(chrc->attrib),
2366 gatt_db_attribute_get_handle(chrc->ccc),
2367 chrc->props & BT_GATT_CHRC_PROP_INDICATE,
2373 static struct io *sock_io_new(int fd, void *user_data)
2379 io_set_close_on_destroy(io, true);
2381 io_set_read_handler(io, sock_io_read, user_data, NULL);
2383 io_set_disconnect_handler(io, sock_hup, user_data, NULL);
2388 static int sock_io_send(struct io *io, const void *data, size_t len)
2393 iov.iov_base = (void *) data;
2396 memset(&msg, 0, sizeof(msg));
2399 return sendmsg(io_get_fd(io), &msg, MSG_NOSIGNAL);
2403 static void acquire_write_reply(DBusMessage *message, void *user_data)
2405 struct pending_op *op = user_data;
2406 struct external_chrc *chrc;
2411 chrc = gatt_db_attribute_get_user_data(op->attrib);
2412 dbus_error_init(&err);
2414 if (dbus_set_error_from_message(&err, message) == TRUE) {
2415 error("Failed to acquire write: %s\n", err.name);
2416 dbus_error_free(&err);
2420 if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
2421 DBUS_TYPE_UINT16, &mtu,
2422 DBUS_TYPE_INVALID) == false)) {
2423 error("Invalid AcquireWrite response\n");
2427 DBG("AcquireWrite success: fd %d MTU %u\n", fd, mtu);
2429 chrc->write_io = sock_io_new(fd, chrc);
2431 if (sock_io_send(chrc->write_io, op->data.iov_base,
2432 op->data.iov_len) < 0)
2435 gatt_db_attribute_write_result(op->attrib, op->id, 0);
2440 send_write(op->device, op->attrib, chrc->proxy, NULL, op->id,
2441 op->data.iov_base, op->data.iov_len, 0,
2445 static void acquire_write_setup(DBusMessageIter *iter, void *user_data)
2447 struct pending_op *op = user_data;
2448 DBusMessageIter dict;
2449 struct bt_gatt_server *server;
2452 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
2453 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
2454 DBUS_TYPE_STRING_AS_STRING
2455 DBUS_TYPE_VARIANT_AS_STRING
2456 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
2459 append_options(&dict, op);
2461 server = btd_device_get_gatt_server(op->device);
2463 mtu = bt_gatt_server_get_mtu(server);
2465 dict_append_entry(&dict, "MTU", DBUS_TYPE_UINT16, &mtu);
2467 dbus_message_iter_close_container(iter, &dict);
2470 static struct pending_op *acquire_write(struct external_chrc *chrc,
2471 struct btd_device *device,
2472 struct gatt_db_attribute *attrib,
2474 const uint8_t *value, size_t len,
2477 struct pending_op *op;
2479 op = pending_write_new(device, NULL, attrib, id, value, len, 0,
2482 if (g_dbus_proxy_method_call(chrc->proxy, "AcquireWrite",
2483 acquire_write_setup,
2484 acquire_write_reply,
2485 op, pending_op_free))
2488 pending_op_free(op);
2493 static void acquire_notify_reply(DBusMessage *message, void *user_data)
2495 struct external_chrc *chrc = user_data;
2500 dbus_error_init(&err);
2502 if (dbus_set_error_from_message(&err, message) == TRUE) {
2503 error("Failed to acquire notify: %s\n", err.name);
2504 dbus_error_free(&err);
2508 if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
2509 DBUS_TYPE_UINT16, &mtu,
2510 DBUS_TYPE_INVALID) == false)) {
2511 error("Invalid AcquirNotify response\n");
2515 DBG("AcquireNotify success: fd %d MTU %u\n", fd, mtu);
2517 chrc->notify_io = sock_io_new(fd, chrc);
2519 __sync_fetch_and_add(&chrc->ntfy_cnt, 1);
2524 g_dbus_proxy_method_call(chrc->proxy, "StartNotify", NULL, NULL,
2527 __sync_fetch_and_add(&chrc->ntfy_cnt, 1);
2530 static void acquire_notify_setup(DBusMessageIter *iter, void *user_data)
2532 DBusMessageIter dict;
2533 struct external_chrc *chrc = user_data;
2535 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
2536 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
2537 DBUS_TYPE_STRING_AS_STRING
2538 DBUS_TYPE_VARIANT_AS_STRING
2539 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
2542 dict_append_entry(&dict, "MTU", DBUS_TYPE_UINT16, &chrc->mtu);
2544 dbus_message_iter_close_container(iter, &dict);
2547 static uint8_t ccc_write_cb(struct bt_att *att, uint16_t value, void *user_data)
2549 struct external_chrc *chrc = user_data;
2550 DBusMessageIter iter;
2552 DBG("External CCC write received with value: 0x%04x", value);
2554 /* Notifications/indications disabled */
2556 if (!chrc->ntfy_cnt)
2559 if (__sync_sub_and_fetch(&chrc->ntfy_cnt, 1))
2562 if (chrc->notify_io) {
2563 io_destroy(chrc->notify_io);
2564 chrc->notify_io = NULL;
2565 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2566 DBG("HUP is not getting generated so calling StopNotify");
2573 * Send request to stop notifying. This is best-effort
2574 * operation, so simply ignore the return the value.
2576 g_dbus_proxy_method_call(chrc->proxy, "StopNotify", NULL,
2581 if (chrc->ntfy_cnt == UINT_MAX) {
2582 /* Maximum number of per-device CCC descriptors configured */
2583 return BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
2586 /* Don't support undefined CCC values yet */
2588 (value == 1 && !(chrc->props & BT_GATT_CHRC_PROP_NOTIFY)) ||
2589 (value == 2 && !(chrc->props & BT_GATT_CHRC_PROP_INDICATE)))
2590 return BT_ERROR_CCC_IMPROPERLY_CONFIGURED;
2592 if (chrc->notify_io) {
2593 __sync_fetch_and_add(&chrc->ntfy_cnt, 1);
2597 chrc->mtu = bt_att_get_mtu(att);
2599 /* Make use of AcquireNotify if supported */
2600 if (g_dbus_proxy_get_property(chrc->proxy, "NotifyAcquired", &iter)) {
2601 if (g_dbus_proxy_method_call(chrc->proxy, "AcquireNotify",
2602 acquire_notify_setup,
2603 acquire_notify_reply,
2609 * Always call StartNotify for an incoming enable and ignore the return
2612 if (g_dbus_proxy_method_call(chrc->proxy, "StartNotify", NULL, NULL,
2613 NULL, NULL) == FALSE)
2614 return BT_ATT_ERROR_UNLIKELY;
2616 __sync_fetch_and_add(&chrc->ntfy_cnt, 1);
2621 static void property_changed_cb(GDBusProxy *proxy, const char *name,
2622 DBusMessageIter *iter, void *user_data)
2624 struct external_chrc *chrc = user_data;
2625 DBusMessageIter array;
2626 uint8_t *value = NULL;
2628 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2629 bool enable = FALSE;
2630 const bdaddr_t *unicast_addr = NULL;
2633 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2634 if (strcmp(name, "Value") == 0) {
2635 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
2636 DBG("Malformed \"Value\" property received");
2640 dbus_message_iter_recurse(iter, &array);
2641 dbus_message_iter_get_fixed_array(&array, &value, &len);
2644 DBG("Malformed \"Value\" property received");
2648 /* Truncate the value if it's too large */
2649 len = MIN(BT_ATT_MAX_VALUE_LEN, len);
2650 value = len ? value : NULL;
2651 } else if (strcmp(name, "Notifying") == 0) {
2652 gboolean notify_indicate = FALSE;
2654 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
2655 DBG("Malformed \"Notifying\" property received");
2659 dbus_message_iter_get_basic(iter, ¬ify_indicate);
2661 DBG("Set Notification %d", notify_indicate);
2662 /* Set notification/indication */
2663 set_ccc_notify_indicate(chrc->ccc, notify_indicate);
2665 } else if (strcmp(name, "Unicast") == 0) {
2666 const char *address = NULL;
2667 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
2668 DBG("Malformed \"Value\" property received");
2672 dbus_message_iter_get_basic(iter, &address);
2675 /* Set the address for unicast notification/indication */
2676 set_ccc_unicast_address(chrc->ccc, address);
2682 enable = get_ccc_notify_indicate(chrc->ccc);
2685 unicast_addr = get_ccc_unicast_address(chrc->ccc);
2687 if (unicast_addr && bacmp(unicast_addr, BDADDR_ANY)) {
2688 send_unicast_notification_indication_to_device(proxy,
2689 chrc->service->app->database,
2690 gatt_db_attribute_get_handle(chrc->attrib),
2692 gatt_db_attribute_get_handle(chrc->ccc),
2693 chrc->props & BT_GATT_CHRC_PROP_INDICATE,
2695 /* reset the unicast address */
2696 set_ccc_unicast_address(chrc->ccc, NULL);
2698 send_notification_indication_to_devices(proxy,
2699 chrc->service->app->database,
2700 gatt_db_attribute_get_handle(chrc->attrib),
2702 gatt_db_attribute_get_handle(chrc->ccc),
2703 chrc->props & BT_GATT_CHRC_PROP_INDICATE);
2706 set_ccc_notify_indicate(chrc->ccc, FALSE);
2709 if (strcmp(name, "Value"))
2712 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
2713 DBG("Malformed \"Value\" property received");
2717 dbus_message_iter_recurse(iter, &array);
2718 dbus_message_iter_get_fixed_array(&array, &value, &len);
2721 DBG("Malformed \"Value\" property received");
2725 /* Truncate the value if it's too large */
2726 len = MIN(BT_ATT_MAX_VALUE_LEN, len);
2727 value = len ? value : NULL;
2729 send_notification_to_devices(chrc->service->app->database,
2730 gatt_db_attribute_get_handle(chrc->attrib),
2732 gatt_db_attribute_get_handle(chrc->ccc),
2733 chrc->props & BT_GATT_CHRC_PROP_INDICATE, proxy);
2737 static bool database_add_ccc(struct external_service *service,
2738 struct external_chrc *chrc)
2740 if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY) &&
2741 !(chrc->props & BT_GATT_CHRC_PROP_INDICATE))
2744 chrc->ccc = service_add_ccc(service->attrib, service->app->database,
2745 ccc_write_cb, chrc, NULL);
2747 error("Failed to create CCC entry for characteristic");
2751 if (g_dbus_proxy_set_property_watch(chrc->proxy, property_changed_cb,
2753 error("Failed to set up property watch for characteristic");
2757 DBG("Created CCC entry for characteristic");
2762 static void cep_write_cb(struct gatt_db_attribute *attrib, int err,
2766 DBG("Failed to store CEP value in the database");
2768 DBG("Stored CEP value in the database");
2771 static bool database_add_cep(struct external_service *service,
2772 struct external_chrc *chrc)
2774 struct gatt_db_attribute *cep;
2778 if (!chrc->ext_props)
2781 bt_uuid16_create(&uuid, GATT_CHARAC_EXT_PROPER_UUID);
2782 cep = gatt_db_service_add_descriptor(service->attrib, &uuid,
2786 error("Failed to create CEP entry for characteristic");
2790 memset(value, 0, sizeof(value));
2791 value[0] = chrc->ext_props;
2793 if (!gatt_db_attribute_write(cep, 0, value, sizeof(value), 0, NULL,
2794 cep_write_cb, NULL)) {
2795 DBG("Failed to store CEP value in the database");
2799 DBG("Created CEP entry for characteristic");
2804 static struct btd_device *att_get_device(struct bt_att *att)
2806 GIOChannel *io = NULL;
2807 GError *gerr = NULL;
2810 struct btd_adapter *adapter;
2812 io = g_io_channel_unix_new(bt_att_get_fd(att));
2816 bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src,
2817 BT_IO_OPT_DEST_BDADDR, &dst,
2818 BT_IO_OPT_DEST_TYPE, &dst_type,
2821 error("bt_io_get: %s", gerr->message);
2823 g_io_channel_unref(io);
2827 g_io_channel_unref(io);
2829 adapter = adapter_find(&src);
2831 error("Unable to find adapter object");
2835 return btd_adapter_find_device(adapter, &dst, dst_type);
2838 static void desc_read_cb(struct gatt_db_attribute *attrib,
2839 unsigned int id, uint16_t offset,
2840 uint8_t opcode, struct bt_att *att,
2843 struct external_desc *desc = user_data;
2844 struct btd_device *device;
2846 if (desc->attrib != attrib) {
2847 error("Read callback called with incorrect attribute");
2851 device = att_get_device(att);
2853 error("Unable to find device object");
2856 if (send_read(device, attrib, desc->proxy, desc->pending_reads, id,
2857 offset, bt_att_get_link_type(att)))
2861 gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY,
2865 static void desc_write_cb(struct gatt_db_attribute *attrib,
2866 unsigned int id, uint16_t offset,
2867 const uint8_t *value, size_t len,
2868 uint8_t opcode, struct bt_att *att,
2871 struct external_desc *desc = user_data;
2872 struct btd_device *device;
2874 if (desc->attrib != attrib) {
2875 error("Read callback called with incorrect attribute");
2879 device = att_get_device(att);
2881 error("Unable to find device object");
2884 if (send_write(device, attrib, desc->proxy, desc->pending_writes, id,
2885 value, len, offset, bt_att_get_link_type(att)))
2889 gatt_db_attribute_write_result(attrib, id, BT_ATT_ERROR_UNLIKELY);
2892 static bool database_add_desc(struct external_service *service,
2893 struct external_desc *desc)
2897 if (!parse_uuid(desc->proxy, &uuid)) {
2898 error("Failed to read \"UUID\" property of descriptor");
2902 desc->attrib = gatt_db_service_add_descriptor(service->attrib, &uuid,
2905 desc_write_cb, desc);
2906 if (!desc->attrib) {
2907 error("Failed to create descriptor entry in database");
2911 desc->handled = true;
2916 static void chrc_read_cb(struct gatt_db_attribute *attrib,
2917 unsigned int id, uint16_t offset,
2918 uint8_t opcode, struct bt_att *att,
2921 struct external_chrc *chrc = user_data;
2922 struct btd_device *device;
2924 if (chrc->attrib != attrib) {
2925 error("Read callback called with incorrect attribute");
2929 device = att_get_device(att);
2931 error("Unable to find device object");
2934 if (send_read(device, attrib, chrc->proxy, chrc->pending_reads, id,
2935 offset, bt_att_get_link_type(att)))
2939 gatt_db_attribute_read_result(attrib, id, BT_ATT_ERROR_UNLIKELY,
2943 static void chrc_write_cb(struct gatt_db_attribute *attrib,
2944 unsigned int id, uint16_t offset,
2945 const uint8_t *value, size_t len,
2946 uint8_t opcode, struct bt_att *att,
2949 struct external_chrc *chrc = user_data;
2950 struct btd_device *device;
2951 struct queue *queue;
2952 DBusMessageIter iter;
2954 if (chrc->attrib != attrib) {
2955 error("Write callback called with incorrect attribute");
2959 device = att_get_device(att);
2961 error("Unable to find device object");
2965 if (chrc->write_io) {
2966 if (sock_io_send(chrc->write_io, value, len) < 0) {
2967 error("Unable to write: %s", strerror(errno));
2971 gatt_db_attribute_write_result(attrib, id, 0);
2975 if (g_dbus_proxy_get_property(chrc->proxy, "WriteAcquired", &iter)) {
2976 if (acquire_write(chrc, device, attrib, id, value, len,
2977 bt_att_get_link_type(att)))
2981 if (!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP))
2982 queue = chrc->pending_writes;
2985 if (send_write(device, attrib, chrc->proxy, queue, id, value, len,
2986 offset, bt_att_get_link_type(att)))
2990 gatt_db_attribute_write_result(attrib, id, BT_ATT_ERROR_UNLIKELY);
2993 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2994 static bool database_check_ccc_desc(struct external_desc *desc)
2996 bt_uuid_t uuid, uuid_ccc;
2998 if (!parse_uuid(desc->proxy, &uuid)) {
2999 error("Failed to read \"UUID\" property of descriptor");
3003 bt_uuid16_create(&uuid_ccc, GATT_CLIENT_CHARAC_CFG_UUID);
3004 if (bt_uuid_cmp(&uuid, &uuid_ccc) == 0)
3011 static bool database_add_chrc(struct external_service *service,
3012 struct external_chrc *chrc)
3015 const struct queue_entry *entry;
3017 if (!parse_uuid(chrc->proxy, &uuid)) {
3018 error("Failed to read \"UUID\" property of characteristic");
3022 if (!check_service_path(chrc->proxy, service)) {
3023 error("Invalid service path for characteristic");
3027 chrc->attrib = gatt_db_service_add_characteristic(service->attrib,
3029 chrc->props, chrc_read_cb,
3030 chrc_write_cb, chrc);
3031 if (!chrc->attrib) {
3032 error("Failed to create characteristic entry in database");
3036 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
3037 /* Existing implementation adds CCC descriptor by default
3038 * if notification and indication properties are set. But as per the requirment
3039 * CCCD shall be added by the application */
3040 if (!database_add_ccc(service, chrc))
3044 if (!database_add_cep(service, chrc))
3047 /* Handle the descriptors that belong to this characteristic. */
3048 for (entry = queue_get_entries(service->descs); entry;
3049 entry = entry->next) {
3050 struct external_desc *desc = entry->data;
3052 if (desc->handled || g_strcmp0(desc->chrc_path, chrc->path))
3055 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
3056 /* Check if Application wants to add CCC and use existing
3057 * implemenation to add CCC descriptors */
3058 if (database_check_ccc_desc(desc)) {
3059 if (!database_add_ccc(service, chrc)) {
3060 chrc->attrib = NULL;
3063 desc->attrib = chrc->ccc;
3064 desc->handled = true;
3065 } else if (!database_add_desc(service, desc)) {
3066 chrc->attrib = NULL;
3067 error("Failed to create descriptor entry");
3071 if (!database_add_desc(service, desc)) {
3072 chrc->attrib = NULL;
3073 error("Failed to create descriptor entry");
3082 static bool match_desc_unhandled(const void *a, const void *b)
3084 const struct external_desc *desc = a;
3086 return !desc->handled;
3089 static bool database_add_service(struct external_service *service)
3093 const struct queue_entry *entry;
3095 if (!parse_uuid(service->proxy, &uuid)) {
3096 error("Failed to read \"UUID\" property of service");
3100 if (!parse_primary(service->proxy, &primary)) {
3101 error("Failed to read \"Primary\" property of service");
3105 service->attrib = gatt_db_add_service(service->app->database->db, &uuid,
3106 primary, service->attr_cnt);
3107 if (!service->attrib)
3110 entry = queue_get_entries(service->chrcs);
3112 struct external_chrc *chrc = entry->data;
3114 if (!database_add_chrc(service, chrc)) {
3115 error("Failed to add characteristic");
3119 entry = entry->next;
3122 /* If there are any unhandled descriptors, return an error */
3123 if (queue_find(service->descs, match_desc_unhandled, NULL)) {
3124 error("Found descriptor with no matching characteristic!");
3128 gatt_db_service_set_active(service->attrib, true);
3133 gatt_db_remove_service(service->app->database->db, service->attrib);
3134 service->attrib = NULL;
3139 static bool database_add_app(struct gatt_app *app)
3141 const struct queue_entry *entry;
3143 entry = queue_get_entries(app->services);
3145 if (!database_add_service(entry->data)) {
3146 error("Failed to add service");
3150 entry = entry->next;
3156 static int profile_device_probe(struct btd_service *service)
3158 struct btd_profile *p = btd_service_get_profile(service);
3160 DBG("%s probed", p->name);
3165 static void profile_device_remove(struct btd_service *service)
3167 struct btd_profile *p = btd_service_get_profile(service);
3169 DBG("%s removed", p->name);
3172 static int profile_device_accept(struct btd_service *service)
3174 struct btd_profile *p = btd_service_get_profile(service);
3176 DBG("%s accept", p->name);
3181 static int profile_add(struct external_profile *profile, const char *uuid)
3183 struct btd_profile *p;
3185 p = new0(struct btd_profile, 1);
3187 /* Assign directly to avoid having extra fields */
3188 p->name = (const void *) g_strdup_printf("%s%s/%s", profile->app->owner,
3189 g_dbus_proxy_get_path(profile->proxy), uuid);
3195 p->remote_uuid = (const void *) g_strdup(uuid);
3196 if (!p->remote_uuid) {
3197 g_free((void *) p->name);
3202 p->device_probe = profile_device_probe;
3203 p->device_remove = profile_device_remove;
3204 p->accept = profile_device_accept;
3205 p->auto_connect = true;
3208 queue_push_tail(profile->profiles, p);
3210 DBG("Added \"%s\"", p->name);
3215 static void add_profile(void *data, void *user_data)
3217 struct btd_adapter *adapter = user_data;
3219 btd_profile_register(data);
3220 adapter_add_profile(adapter, data);
3223 static struct external_profile *create_profile(struct gatt_app *app,
3227 struct external_profile *profile;
3228 DBusMessageIter iter, array;
3230 if (!path || !g_str_has_prefix(path, "/"))
3233 profile = new0(struct external_profile, 1);
3236 profile->proxy = g_dbus_proxy_ref(proxy);
3237 profile->profiles = queue_new();
3239 if (!g_dbus_proxy_get_property(proxy, "UUIDs", &iter)) {
3240 DBG("UUIDs property not found");
3244 dbus_message_iter_recurse(&iter, &array);
3246 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
3249 dbus_message_iter_get_basic(&array, &uuid);
3251 if (profile_add(profile, uuid) < 0)
3254 dbus_message_iter_next(&array);
3257 if (queue_isempty(profile->profiles))
3260 queue_foreach(profile->profiles, add_profile, app->database->adapter);
3261 queue_push_tail(app->profiles, profile);
3266 profile_free(profile);
3270 static void register_profile(void *data, void *user_data)
3272 struct gatt_app *app = user_data;
3273 GDBusProxy *proxy = data;
3274 const char *iface = g_dbus_proxy_get_interface(proxy);
3275 const char *path = g_dbus_proxy_get_path(proxy);
3280 if (g_strcmp0(iface, GATT_PROFILE_IFACE) == 0) {
3281 struct external_profile *profile;
3283 profile = create_profile(app, proxy, path);
3291 static void register_service(void *data, void *user_data)
3293 struct gatt_app *app = user_data;
3294 GDBusProxy *proxy = data;
3295 const char *iface = g_dbus_proxy_get_interface(proxy);
3296 const char *path = g_dbus_proxy_get_path(proxy);
3301 if (g_strcmp0(iface, GATT_SERVICE_IFACE) == 0) {
3302 struct external_service *service;
3304 service = create_service(app, proxy, path);
3312 static void register_characteristic(void *data, void *user_data)
3314 struct gatt_app *app = user_data;
3315 GDBusProxy *proxy = data;
3316 const char *iface = g_dbus_proxy_get_interface(proxy);
3317 const char *path = g_dbus_proxy_get_path(proxy);
3322 iface = g_dbus_proxy_get_interface(proxy);
3323 path = g_dbus_proxy_get_path(proxy);
3325 if (g_strcmp0(iface, GATT_CHRC_IFACE) == 0) {
3326 struct external_chrc *chrc;
3328 chrc = chrc_create(app, proxy, path);
3336 static void register_descriptor(void *data, void *user_data)
3338 struct gatt_app *app = user_data;
3339 GDBusProxy *proxy = data;
3340 const char *iface = g_dbus_proxy_get_interface(proxy);
3345 if (g_strcmp0(iface, GATT_DESC_IFACE) == 0) {
3346 struct external_desc *desc;
3348 desc = desc_create(app, proxy);
3356 static void client_ready_cb(GDBusClient *client, void *user_data)
3358 struct gatt_app *app = user_data;
3363 * Process received objects
3365 if (queue_isempty(app->proxies)) {
3366 error("No object received");
3368 reply = btd_error_failed(app->reg,
3369 "No object received");
3373 queue_foreach(app->proxies, register_profile, app);
3374 queue_foreach(app->proxies, register_service, app);
3375 queue_foreach(app->proxies, register_characteristic, app);
3376 queue_foreach(app->proxies, register_descriptor, app);
3378 if ((queue_isempty(app->services) && queue_isempty(app->profiles)) ||
3380 error("No valid external GATT objects found");
3382 reply = btd_error_failed(app->reg,
3383 "No valid service object found");
3387 if (!database_add_app(app)) {
3388 error("Failed to create GATT service entry in local database");
3390 reply = btd_error_failed(app->reg,
3391 "Failed to create entry in database");
3395 DBG("GATT application registered: %s:%s", app->owner, app->path);
3397 reply = dbus_message_new_method_return(app->reg);
3400 g_dbus_send_message(btd_get_dbus_connection(), reply);
3401 dbus_message_unref(app->reg);
3408 static struct gatt_app *create_app(DBusConnection *conn, DBusMessage *msg,
3411 struct gatt_app *app;
3412 const char *sender = dbus_message_get_sender(msg);
3414 if (!path || !g_str_has_prefix(path, "/"))
3417 app = new0(struct gatt_app, 1);
3419 app->client = g_dbus_client_new_full(conn, sender, path, path);
3423 app->owner = g_strdup(sender);
3427 app->path = g_strdup(path);
3431 app->services = queue_new();
3432 app->profiles = queue_new();
3433 app->proxies = queue_new();
3434 app->reg = dbus_message_ref(msg);
3436 g_dbus_client_set_disconnect_watch(app->client, client_disconnect_cb,
3438 g_dbus_client_set_proxy_handlers(app->client, proxy_added_cb,
3439 proxy_removed_cb, NULL, app);
3440 g_dbus_client_set_ready_watch(app->client, client_ready_cb, app);
3449 static DBusMessage *manager_register_app(DBusConnection *conn,
3450 DBusMessage *msg, void *user_data)
3452 struct btd_gatt_database *database = user_data;
3453 const char *sender = dbus_message_get_sender(msg);
3454 DBusMessageIter args;
3456 struct gatt_app *app;
3457 struct svc_match_data match_data;
3459 if (!dbus_message_iter_init(msg, &args))
3460 return btd_error_invalid_args(msg);
3462 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
3463 return btd_error_invalid_args(msg);
3465 dbus_message_iter_get_basic(&args, &path);
3467 match_data.path = path;
3468 match_data.sender = sender;
3470 if (queue_find(database->apps, match_app, &match_data))
3471 return btd_error_already_exists(msg);
3473 dbus_message_iter_next(&args);
3474 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
3475 return btd_error_invalid_args(msg);
3477 app = create_app(conn, msg, path);
3479 return btd_error_failed(msg, "Failed to register application");
3481 DBG("Registering application: %s:%s", sender, path);
3483 app->database = database;
3484 queue_push_tail(database->apps, app);
3489 static DBusMessage *manager_unregister_app(DBusConnection *conn,
3490 DBusMessage *msg, void *user_data)
3492 struct btd_gatt_database *database = user_data;
3493 const char *sender = dbus_message_get_sender(msg);
3495 DBusMessageIter args;
3496 struct gatt_app *app;
3497 struct svc_match_data match_data;
3499 if (!dbus_message_iter_init(msg, &args))
3500 return btd_error_invalid_args(msg);
3502 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
3503 return btd_error_invalid_args(msg);
3505 dbus_message_iter_get_basic(&args, &path);
3507 match_data.path = path;
3508 match_data.sender = sender;
3510 app = queue_remove_if(database->apps, match_app, &match_data);
3512 return btd_error_does_not_exist(msg);
3516 return dbus_message_new_method_return(msg);
3519 static const GDBusMethodTable manager_methods[] = {
3520 { GDBUS_ASYNC_METHOD("RegisterApplication",
3521 GDBUS_ARGS({ "application", "o" },
3522 { "options", "a{sv}" }),
3523 NULL, manager_register_app) },
3524 { GDBUS_ASYNC_METHOD("UnregisterApplication",
3525 GDBUS_ARGS({ "application", "o" }),
3526 NULL, manager_unregister_app) },
3530 struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter)
3532 struct btd_gatt_database *database;
3533 GError *gerr = NULL;
3534 const bdaddr_t *addr;
3539 database = new0(struct btd_gatt_database, 1);
3540 database->adapter = btd_adapter_ref(adapter);
3541 database->db = gatt_db_new();
3542 database->records = queue_new();
3543 database->device_states = queue_new();
3544 database->apps = queue_new();
3545 database->profiles = queue_new();
3546 database->ccc_callbacks = queue_new();
3548 addr = btd_adapter_get_address(adapter);
3549 database->le_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,
3550 BT_IO_OPT_SOURCE_BDADDR, addr,
3551 BT_IO_OPT_SOURCE_TYPE,
3552 btd_adapter_get_address_type(adapter),
3553 BT_IO_OPT_CID, ATT_CID,
3554 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
3556 if (!database->le_io) {
3557 error("Failed to start listening: %s", gerr->message);
3563 database->l2cap_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,
3564 BT_IO_OPT_SOURCE_BDADDR, addr,
3565 BT_IO_OPT_PSM, ATT_PSM,
3566 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
3568 if (database->l2cap_io == NULL) {
3569 error("Failed to start listening: %s", gerr->message);
3574 if (g_dbus_register_interface(btd_get_dbus_connection(),
3575 adapter_get_path(adapter),
3577 manager_methods, NULL, NULL,
3579 DBG("GATT Manager registered for adapter: %s",
3580 adapter_get_path(adapter));
3582 register_core_services(database);
3584 database->db_id = gatt_db_register(database->db, gatt_db_service_added,
3585 gatt_db_service_removed,
3588 if (!database->db_id)
3594 gatt_database_free(database);
3599 void btd_gatt_database_destroy(struct btd_gatt_database *database)
3604 g_dbus_unregister_interface(btd_get_dbus_connection(),
3605 adapter_get_path(database->adapter),
3606 GATT_MANAGER_IFACE);
3608 gatt_database_free(database);
3611 struct gatt_db *btd_gatt_database_get_db(struct btd_gatt_database *database)
3616 return database->db;