gatt: Omit MTU if not connected
[platform/upstream/bluez.git] / src / gatt-client.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2014  Google Inc.
7  *
8  *
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <stdbool.h>
16 #include <stdint.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20
21 #include <dbus/dbus.h>
22
23 #include "lib/bluetooth.h"
24 #include "lib/sdp.h"
25 #include "lib/uuid.h"
26
27 #include "gdbus/gdbus.h"
28 #include "btio/btio.h"
29
30 #include "log.h"
31 #include "error.h"
32 #include "btd.h"
33 #include "adapter.h"
34 #include "device.h"
35 #include "src/shared/io.h"
36 #include "src/shared/queue.h"
37 #include "src/shared/att.h"
38 #include "src/shared/gatt-db.h"
39 #include "src/shared/gatt-client.h"
40 #include "src/shared/util.h"
41 #include "gatt-client.h"
42 #include "dbus-common.h"
43
44 #ifndef NELEM
45 #define NELEM(x) (sizeof(x) / sizeof((x)[0]))
46 #endif
47
48 #define GATT_SERVICE_IFACE              "org.bluez.GattService1"
49 #define GATT_CHARACTERISTIC_IFACE       "org.bluez.GattCharacteristic1"
50 #define GATT_DESCRIPTOR_IFACE           "org.bluez.GattDescriptor1"
51
52 struct btd_gatt_client {
53         struct btd_device *device;
54         uint8_t features;
55         bool ready;
56         char devaddr[18];
57         struct gatt_db *db;
58         struct bt_gatt_client *gatt;
59
60         struct queue *services;
61         struct queue *all_notify_clients;
62         struct queue *ios;
63 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
64         guint wait_charcs_id;
65 #endif
66 };
67
68 struct service {
69         struct btd_gatt_client *client;
70         bool primary;
71         uint16_t start_handle;
72         uint16_t end_handle;
73         bt_uuid_t uuid;
74         char *path;
75         struct queue *chrcs;
76         struct queue *incl_services;
77 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
78         bool chrcs_ready;
79         struct queue *pending_ext_props;
80         guint idle_id;
81 #endif
82 };
83
84 typedef bool (*async_dbus_op_complete_t)(void *data);
85
86 struct async_dbus_op {
87         int ref_count;
88         unsigned int id;
89         struct queue *msgs;
90         void *data;
91         uint16_t offset;
92         async_dbus_op_complete_t complete;
93 };
94
95 struct sock_io {
96         DBusMessage *msg;
97         struct io *io;
98         void (*destroy)(void *data);
99         void *data;
100 };
101
102 struct characteristic {
103         struct service *service;
104         struct gatt_db_attribute *attr;
105         uint16_t handle;
106         uint16_t value_handle;
107         uint8_t props;
108         uint16_t ext_props;
109         uint16_t ext_props_handle;
110         bt_uuid_t uuid;
111         char *path;
112
113         unsigned int ready_id;
114         unsigned int exchange_id;
115         struct sock_io *write_io;
116         struct sock_io *notify_io;
117
118         struct async_dbus_op *read_op;
119         struct async_dbus_op *write_op;
120
121         struct queue *descs;
122
123         bool notifying;
124         struct queue *notify_clients;
125 };
126
127 struct descriptor {
128         struct characteristic *chrc;
129         struct gatt_db_attribute *attr;
130         uint16_t handle;
131         bt_uuid_t uuid;
132         char *path;
133
134         struct async_dbus_op *read_op;
135         struct async_dbus_op *write_op;
136 };
137
138 static bool uuid_cmp(const bt_uuid_t *uuid, uint16_t u16)
139 {
140         bt_uuid_t uuid16;
141
142         bt_uuid16_create(&uuid16, u16);
143
144         return bt_uuid_cmp(uuid, &uuid16) == 0;
145 }
146
147 static gboolean descriptor_get_uuid(const GDBusPropertyTable *property,
148                                         DBusMessageIter *iter, void *data)
149 {
150         char uuid[MAX_LEN_UUID_STR + 1];
151         const char *ptr = uuid;
152         struct descriptor *desc = data;
153
154         bt_uuid_to_string(&desc->uuid, uuid, sizeof(uuid));
155         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
156
157         return TRUE;
158 }
159
160 static gboolean descriptor_get_characteristic(
161                                         const GDBusPropertyTable *property,
162                                         DBusMessageIter *iter, void *data)
163 {
164         struct descriptor *desc = data;
165         const char *str = desc->chrc->path;
166
167         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &str);
168
169         return TRUE;
170 }
171
172 static void read_cb(struct gatt_db_attribute *attrib, int err,
173                                 const uint8_t *value, size_t length,
174                                 void *user_data)
175 {
176         DBusMessageIter *array = user_data;
177
178         if (err)
179                 return;
180
181         dbus_message_iter_append_fixed_array(array, DBUS_TYPE_BYTE, &value,
182                                                                 length);
183 }
184
185 static gboolean descriptor_get_value(const GDBusPropertyTable *property,
186                                         DBusMessageIter *iter, void *data)
187 {
188         struct descriptor *desc = data;
189         DBusMessageIter array;
190
191         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
192
193         gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_cb, &array);
194
195         dbus_message_iter_close_container(iter, &array);
196
197         return TRUE;
198 }
199
200 static void read_check_cb(struct gatt_db_attribute *attrib, int err,
201                                 const uint8_t *value, size_t length,
202                                 void *user_data)
203 {
204         gboolean *ret = user_data;
205
206         if (err) {
207                 *ret = FALSE;
208                 return;
209         }
210
211         *ret = TRUE;
212 }
213
214 static gboolean descriptor_value_exists(const GDBusPropertyTable *property,
215                                                                 void *data)
216 {
217         struct descriptor *desc = data;
218         gboolean ret;
219
220         gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_check_cb, &ret);
221
222         return ret;
223 }
224
225 static int parse_value_arg(DBusMessageIter *iter, uint8_t **value, int *len)
226 {
227         DBusMessageIter array;
228
229         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
230                 return -EINVAL;
231
232         dbus_message_iter_recurse(iter, &array);
233         dbus_message_iter_get_fixed_array(&array, value, len);
234
235         return 0;
236 }
237
238 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
239 static int parse_type_value_arg(DBusMessageIter *iter, uint8_t *type, uint8_t **value,
240                                                         int *len)
241 {
242         DBusMessageIter array;
243
244         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BYTE)
245                 return -EINVAL;
246         dbus_message_iter_get_basic(iter, type);
247         dbus_message_iter_next(iter);
248         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
249                 return -EINVAL;
250
251         dbus_message_iter_recurse(iter, &array);
252         dbus_message_iter_get_fixed_array(&array, value, len);
253
254         return 0;
255 }
256 #endif
257
258 static void async_dbus_op_free(void *data)
259 {
260         struct async_dbus_op *op = data;
261
262         queue_destroy(op->msgs, (void *)dbus_message_unref);
263
264         free(op);
265 }
266
267 static struct async_dbus_op *async_dbus_op_ref(struct async_dbus_op *op)
268 {
269         __sync_fetch_and_add(&op->ref_count, 1);
270
271         return op;
272 }
273
274 static void async_dbus_op_unref(void *data)
275 {
276         struct async_dbus_op *op = data;
277
278         if (__sync_sub_and_fetch(&op->ref_count, 1))
279                 return;
280
281         async_dbus_op_free(op);
282 }
283
284 static void message_append_byte_array(DBusMessage *msg, const uint8_t *bytes,
285                                                                 size_t len)
286 {
287         DBusMessageIter iter, array;
288
289         dbus_message_iter_init_append(msg, &iter);
290         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "y", &array);
291         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, &bytes,
292                                                                         len);
293         dbus_message_iter_close_container(&iter, &array);
294 }
295
296 static DBusMessage *create_gatt_dbus_error(DBusMessage *msg, uint8_t att_ecode)
297 {
298 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
299         return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
300                         "Operation failed with ATT error: 0x%02x",
301                         att_ecode);
302 #else
303         switch (att_ecode) {
304         case BT_ATT_ERROR_READ_NOT_PERMITTED:
305                 return btd_error_not_permitted(msg, "Read not permitted");
306         case BT_ATT_ERROR_WRITE_NOT_PERMITTED:
307                 return btd_error_not_permitted(msg, "Write not permitted");
308         case BT_ATT_ERROR_AUTHENTICATION:
309         case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION:
310         case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE:
311                 return btd_error_not_permitted(msg, "Not paired");
312         case BT_ATT_ERROR_INVALID_OFFSET:
313                 return btd_error_invalid_args_str(msg, "Invalid offset");
314         case BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN:
315                 return btd_error_invalid_args_str(msg, "Invalid Length");
316         case BT_ATT_ERROR_AUTHORIZATION:
317                 return btd_error_not_authorized(msg);
318         case BT_ATT_ERROR_REQUEST_NOT_SUPPORTED:
319                 return btd_error_not_supported(msg);
320         case 0:
321                 return btd_error_failed(msg, "Operation failed");
322         default:
323                 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
324                                 "Operation failed with ATT error: 0x%02x",
325                                 att_ecode);
326         }
327
328         return NULL;
329 #endif
330 }
331
332 static void write_descriptor_cb(struct gatt_db_attribute *attr, int err,
333                                                                 void *user_data)
334 {
335         struct descriptor *desc = user_data;
336
337         if (err)
338                 return;
339
340         g_dbus_emit_property_changed(btd_get_dbus_connection(), desc->path,
341                                         GATT_DESCRIPTOR_IFACE, "Value");
342 }
343
344 static void async_dbus_op_reply(struct async_dbus_op *op, int err,
345                                 const uint8_t *value, ssize_t length)
346 {
347         const struct queue_entry *entry;
348         DBusMessage *reply;
349
350         op->id = 0;
351
352         for (entry = queue_get_entries(op->msgs); entry; entry = entry->next) {
353                 DBusMessage *msg = entry->data;
354
355                 if (err) {
356                         reply = err > 0 ? create_gatt_dbus_error(msg, err) :
357                                 btd_error_failed(msg, strerror(-err));
358                         goto send_reply;
359                 }
360
361                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
362                 if (!reply) {
363                         error("Failed to allocate D-Bus message reply");
364                         return;
365                 }
366
367                 if (length >= 0)
368                         message_append_byte_array(reply, value, length);
369
370 send_reply:
371                 g_dbus_send_message(btd_get_dbus_connection(), reply);
372         }
373 }
374
375 static void read_op_cb(struct gatt_db_attribute *attrib, int err,
376                                 const uint8_t *value, size_t length,
377                                 void *user_data)
378 {
379         struct async_dbus_op *op = user_data;
380
381         async_dbus_op_reply(op, err, value, length);
382 }
383
384 static void desc_read_cb(bool success, uint8_t att_ecode,
385                                         const uint8_t *value, uint16_t length,
386                                         void *user_data)
387 {
388         struct async_dbus_op *op = user_data;
389         struct descriptor *desc = op->data;
390
391         if (!success)
392                 goto fail;
393
394         if (!op->offset)
395                 gatt_db_attribute_reset(desc->attr);
396
397         if (!gatt_db_attribute_write(desc->attr, op->offset, value, length, 0,
398                                         NULL, write_descriptor_cb, desc)) {
399                 error("Failed to store attribute");
400                 att_ecode = BT_ATT_ERROR_UNLIKELY;
401                 goto fail;
402         }
403
404         /* Read the stored data from db */
405         if (!gatt_db_attribute_read(desc->attr, op->offset, 0, NULL, read_op_cb,
406                                                                         op)) {
407                 error("Failed to read database");
408                 att_ecode = BT_ATT_ERROR_UNLIKELY;
409                 goto fail;
410         }
411
412         desc->read_op = NULL;
413
414         return;
415
416 fail:
417         async_dbus_op_reply(op, att_ecode, NULL, 0);
418         desc->read_op = NULL;
419 }
420
421 static int parse_options(DBusMessageIter *iter, uint16_t *offset,
422                                                 const char **type)
423 {
424         DBusMessageIter dict;
425
426         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
427                 return -EINVAL;
428
429         dbus_message_iter_recurse(iter, &dict);
430
431         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
432                 const char *key;
433                 DBusMessageIter value, entry;
434                 int var;
435
436                 dbus_message_iter_recurse(&dict, &entry);
437                 dbus_message_iter_get_basic(&entry, &key);
438
439                 dbus_message_iter_next(&entry);
440                 dbus_message_iter_recurse(&entry, &value);
441
442                 var = dbus_message_iter_get_arg_type(&value);
443                 if (strcasecmp(key, "offset") == 0) {
444                         if (var != DBUS_TYPE_UINT16)
445                                 return -EINVAL;
446                         dbus_message_iter_get_basic(&value, offset);
447                 }
448
449                 if (type && strcasecmp(key, "type") == 0) {
450                         if (var != DBUS_TYPE_STRING)
451                                 return -EINVAL;
452                         dbus_message_iter_get_basic(&value, type);
453                 }
454
455                 dbus_message_iter_next(&dict);
456         }
457
458         return 0;
459 }
460
461 static struct async_dbus_op *async_dbus_op_new(DBusMessage *msg, void *data)
462 {
463         struct async_dbus_op *op;
464
465         op = new0(struct async_dbus_op, 1);
466         op->msgs = queue_new();
467         queue_push_tail(op->msgs, dbus_message_ref(msg));
468         op->data = data;
469
470         return op;
471 }
472
473 static struct async_dbus_op *read_value(struct bt_gatt_client *gatt,
474                                         DBusMessage *msg, uint16_t handle,
475                                         uint16_t offset,
476                                         bt_gatt_client_read_callback_t callback,
477                                         void *data)
478 {
479         struct async_dbus_op *op;
480
481         op = async_dbus_op_new(msg, data);
482         op->offset = offset;
483
484         op->id = bt_gatt_client_read_long_value(gatt, handle, offset, callback,
485                                                 async_dbus_op_ref(op),
486                                                 async_dbus_op_unref);
487         if (op->id)
488                 return op;
489
490         async_dbus_op_free(op);
491
492         return NULL;
493 }
494
495 static DBusMessage *descriptor_read_value(DBusConnection *conn,
496                                         DBusMessage *msg, void *user_data)
497 {
498         struct descriptor *desc = user_data;
499         struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
500         DBusMessageIter iter;
501         uint16_t offset = 0;
502
503         if (!gatt)
504                 return btd_error_failed(msg, "Not connected");
505
506         dbus_message_iter_init(msg, &iter);
507
508         if (parse_options(&iter, &offset, NULL))
509                 return btd_error_invalid_args(msg);
510
511         if (desc->read_op) {
512                 if (desc->read_op->offset != offset)
513                         return btd_error_in_progress(msg);
514                 queue_push_tail(desc->read_op->msgs, dbus_message_ref(msg));
515                 return NULL;
516         }
517
518         desc->read_op = read_value(gatt, msg, desc->handle, offset,
519                                                         desc_read_cb, desc);
520         if (!desc->read_op)
521                 return btd_error_failed(msg, "Failed to send read request");
522
523         return NULL;
524 }
525
526 static void write_result_cb(bool success, bool reliable_error,
527                                         uint8_t att_ecode, void *user_data)
528 {
529         struct async_dbus_op *op = user_data;
530         int err = 0;
531
532         if (op->complete && !op->complete(op->data)) {
533                 err = -EFAULT;
534                 goto done;
535         }
536
537         if (!success) {
538                 if (reliable_error)
539                         err = -EFAULT;
540                 else
541                         err = att_ecode;
542         }
543
544 done:
545         async_dbus_op_reply(op, err, NULL, -1);
546 }
547
548 static void write_cb(bool success, uint8_t att_ecode, void *user_data)
549 {
550         write_result_cb(success, false, att_ecode, user_data);
551 }
552
553 static struct async_dbus_op *start_long_write(DBusMessage *msg, uint16_t handle,
554                                         struct bt_gatt_client *gatt,
555                                         bool reliable, const uint8_t *value,
556                                         size_t value_len, uint16_t offset,
557                                         void *data,
558                                         async_dbus_op_complete_t complete)
559 {
560         struct async_dbus_op *op;
561
562         op = async_dbus_op_new(msg, data);
563         op->complete = complete;
564         op->offset = offset;
565
566         op->id = bt_gatt_client_write_long_value(gatt, reliable, handle, offset,
567                                                         value, value_len,
568                                                         write_result_cb, op,
569                                                         async_dbus_op_free);
570
571         if (!op->id) {
572                 async_dbus_op_free(op);
573                 return NULL;
574         }
575
576         return op;
577 }
578
579 static struct async_dbus_op *start_write_request(DBusMessage *msg,
580                                         uint16_t handle,
581                                         struct bt_gatt_client *gatt,
582                                         const uint8_t *value, size_t value_len,
583                                         void *data,
584                                         async_dbus_op_complete_t complete)
585 {
586         struct async_dbus_op *op;
587
588         op = async_dbus_op_new(msg, data);
589         op->complete = complete;
590
591         op->id = bt_gatt_client_write_value(gatt, handle, value, value_len,
592                                                         write_cb, op,
593                                                         async_dbus_op_free);
594         if (!op->id) {
595                 async_dbus_op_free(op);
596                 return NULL;
597         }
598
599         return op;
600 }
601 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
602 static struct async_dbus_op *start_write_cmd(DBusMessage *msg, uint16_t handle,
603                                 struct bt_gatt_client *gatt, bool signed_write,
604                                 const uint8_t *value, size_t value_len,
605                                 void *data, async_dbus_op_complete_t complete)
606 {
607         struct async_dbus_op *op;
608
609         op = async_dbus_op_new(msg, data);
610         op->complete = complete;
611
612         op->id = bt_gatt_client_write_without_response_async(gatt, handle,
613                         signed_write, value, value_len,
614                         write_cb, op, async_dbus_op_free);
615
616         if (!op->id) {
617                 async_dbus_op_free(op);
618                 return NULL;
619         }
620
621         return op;
622 }
623 #endif
624
625 static bool desc_write_complete(void *data)
626 {
627         struct descriptor *desc = data;
628
629         desc->write_op = NULL;
630
631         /*
632          * The descriptor might have been unregistered during the read. Return
633          * failure.
634          */
635         return !!desc->chrc;
636 }
637
638 static DBusMessage *descriptor_write_value(DBusConnection *conn,
639                                         DBusMessage *msg, void *user_data)
640 {
641         struct descriptor *desc = user_data;
642         struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
643         DBusMessageIter iter;
644         uint8_t *value = NULL;
645         int value_len = 0;
646         uint16_t offset = 0;
647
648         if (!gatt)
649                 return btd_error_failed(msg, "Not connected");
650
651         if (desc->write_op)
652                 return btd_error_in_progress(msg);
653
654         dbus_message_iter_init(msg, &iter);
655
656         if (parse_value_arg(&iter, &value, &value_len))
657                 return btd_error_invalid_args(msg);
658
659         dbus_message_iter_next(&iter);
660
661         if (parse_options(&iter, &offset, NULL))
662                 return btd_error_invalid_args(msg);
663
664         /*
665          * Don't allow writing to Client Characteristic Configuration
666          * descriptors. We achieve this through the StartNotify and StopNotify
667          * methods on GattCharacteristic1.
668          */
669         if (uuid_cmp(&desc->uuid, GATT_CLIENT_CHARAC_CFG_UUID))
670                 return btd_error_not_permitted(msg, "Write not permitted");
671
672         /*
673          * Based on the value length and the MTU, either use a write or a long
674          * write.
675          */
676         if (value_len <= bt_gatt_client_get_mtu(gatt) - 3 && !offset)
677                 desc->write_op = start_write_request(msg, desc->handle,
678                                                         gatt, value,
679                                                         value_len, desc,
680                                                         desc_write_complete);
681         else
682                 desc->write_op = start_long_write(msg, desc->handle, gatt,
683                                                         false, value,
684                                                         value_len, offset, desc,
685                                                         desc_write_complete);
686
687         if (!desc->write_op)
688                 return btd_error_failed(msg, "Failed to initiate write");
689
690         return NULL;
691 }
692
693 static const GDBusPropertyTable descriptor_properties[] = {
694         { "UUID", "s", descriptor_get_uuid },
695         { "Characteristic", "o", descriptor_get_characteristic, },
696         { "Value", "ay", descriptor_get_value, NULL, descriptor_value_exists },
697         { }
698 };
699
700 static const GDBusMethodTable descriptor_methods[] = {
701         { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
702                                         GDBUS_ARGS({ "value", "ay" }),
703                                         descriptor_read_value) },
704         { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
705                                                 { "options", "a{sv}" }),
706                                         NULL,
707                                         descriptor_write_value) },
708         { }
709 };
710
711 static void descriptor_free(void *data)
712 {
713         struct descriptor *desc = data;
714
715         g_free(desc->path);
716         free(desc);
717 }
718
719 static struct descriptor *descriptor_create(struct gatt_db_attribute *attr,
720                                                 struct characteristic *chrc)
721 {
722         struct descriptor *desc;
723
724         desc = new0(struct descriptor, 1);
725         desc->chrc = chrc;
726         desc->attr = attr;
727         desc->handle = gatt_db_attribute_get_handle(attr);
728
729         bt_uuid_to_uuid128(gatt_db_attribute_get_type(attr), &desc->uuid);
730
731         desc->path = g_strdup_printf("%s/desc%04x", chrc->path, desc->handle);
732
733         if (!g_dbus_register_interface(btd_get_dbus_connection(), desc->path,
734                                                 GATT_DESCRIPTOR_IFACE,
735                                                 descriptor_methods, NULL,
736                                                 descriptor_properties,
737                                                 desc, descriptor_free)) {
738                 error("Unable to register GATT descriptor with handle 0x%04x",
739                                                                 desc->handle);
740                 descriptor_free(desc);
741
742                 return NULL;
743         }
744
745         DBG("Exported GATT characteristic descriptor: %s", desc->path);
746
747         if (uuid_cmp(&desc->uuid, GATT_CHARAC_EXT_PROPER_UUID))
748                 chrc->ext_props_handle = desc->handle;
749
750         return desc;
751 }
752
753 static void unregister_descriptor(void *data)
754 {
755         struct descriptor *desc = data;
756         struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
757
758         DBG("Removing GATT descriptor: %s", desc->path);
759
760         if (desc->read_op)
761                 bt_gatt_client_cancel(gatt, desc->read_op->id);
762
763         if (desc->write_op)
764                 bt_gatt_client_cancel(gatt, desc->write_op->id);
765
766         desc->chrc = NULL;
767
768         g_dbus_unregister_interface(btd_get_dbus_connection(), desc->path,
769                                                         GATT_DESCRIPTOR_IFACE);
770 }
771
772 static gboolean characteristic_get_uuid(const GDBusPropertyTable *property,
773                                         DBusMessageIter *iter, void *data)
774 {
775         char uuid[MAX_LEN_UUID_STR + 1];
776         const char *ptr = uuid;
777         struct characteristic *chrc = data;
778
779         bt_uuid_to_string(&chrc->uuid, uuid, sizeof(uuid));
780         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
781
782         return TRUE;
783 }
784
785 static gboolean characteristic_get_service(const GDBusPropertyTable *property,
786                                         DBusMessageIter *iter, void *data)
787 {
788         struct characteristic *chrc = data;
789         const char *str = chrc->service->path;
790
791         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &str);
792
793         return TRUE;
794 }
795
796 static gboolean characteristic_get_value(const GDBusPropertyTable *property,
797                                         DBusMessageIter *iter, void *data)
798 {
799         struct characteristic *chrc = data;
800         DBusMessageIter array;
801
802         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
803
804         gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_cb, &array);
805
806         dbus_message_iter_close_container(iter, &array);
807
808         return TRUE;
809 }
810
811 static gboolean characteristic_value_exists(const GDBusPropertyTable *property,
812                                                                 void *data)
813 {
814         struct characteristic *chrc = data;
815         gboolean ret;
816
817         gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_check_cb, &ret);
818
819         return ret;
820 }
821
822 static gboolean characteristic_get_notifying(const GDBusPropertyTable *property,
823                                         DBusMessageIter *iter, void *data)
824 {
825         struct characteristic *chrc = data;
826         dbus_bool_t notifying = chrc->notifying ? TRUE : FALSE;
827
828         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &notifying);
829
830         return TRUE;
831 }
832
833 static gboolean
834 characteristic_notifying_exists(const GDBusPropertyTable *property, void *data)
835 {
836         struct characteristic *chrc = data;
837
838         return (chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
839                                 chrc->props & BT_GATT_CHRC_PROP_INDICATE);
840 }
841
842 struct chrc_prop_data {
843         uint8_t prop;
844         char *str;
845 };
846
847 static struct chrc_prop_data chrc_props[] = {
848         /* Default Properties */
849         { BT_GATT_CHRC_PROP_BROADCAST,          "broadcast" },
850         { BT_GATT_CHRC_PROP_READ,               "read" },
851         { BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP, "write-without-response" },
852         { BT_GATT_CHRC_PROP_WRITE,              "write" },
853         { BT_GATT_CHRC_PROP_NOTIFY,             "notify" },
854         { BT_GATT_CHRC_PROP_INDICATE,           "indicate" },
855         { BT_GATT_CHRC_PROP_AUTH,               "authenticated-signed-writes" },
856         { BT_GATT_CHRC_PROP_EXT_PROP,           "extended-properties" }
857 };
858
859 static struct chrc_prop_data chrc_ext_props[] = {
860         /* Extended Properties */
861         { BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE, "reliable-write" },
862         { BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX,   "writable-auxiliaries" }
863 };
864
865 static gboolean characteristic_get_flags(const GDBusPropertyTable *property,
866                                         DBusMessageIter *iter, void *data)
867 {
868         struct characteristic *chrc = data;
869         DBusMessageIter array;
870         unsigned i;
871
872         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
873
874         for (i = 0; i < NELEM(chrc_props); i++) {
875                 if (chrc->props & chrc_props[i].prop)
876                         dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
877                                                         &chrc_props[i].str);
878         }
879
880         for (i = 0; i < NELEM(chrc_ext_props); i++) {
881                 if (chrc->ext_props & chrc_ext_props[i].prop)
882                         dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
883                                                         &chrc_ext_props[i].str);
884         }
885
886         dbus_message_iter_close_container(iter, &array);
887
888         return TRUE;
889 }
890
891 static gboolean
892 characteristic_get_write_acquired(const GDBusPropertyTable *property,
893                                         DBusMessageIter *iter, void *data)
894 {
895         struct characteristic *chrc = data;
896         dbus_bool_t locked = chrc->write_io ? TRUE : FALSE;
897
898         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &locked);
899
900         return TRUE;
901 }
902
903 static gboolean
904 characteristic_write_acquired_exists(const GDBusPropertyTable *property,
905                                                                 void *data)
906 {
907         struct characteristic *chrc = data;
908
909         return (chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP);
910 }
911
912 static gboolean
913 characteristic_get_notify_acquired(const GDBusPropertyTable *property,
914                                         DBusMessageIter *iter, void *data)
915 {
916         struct characteristic *chrc = data;
917         dbus_bool_t locked = chrc->notify_io ? TRUE : FALSE;
918
919         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &locked);
920
921         return TRUE;
922 }
923
924 static gboolean
925 characteristic_notify_acquired_exists(const GDBusPropertyTable *property,
926                                                                 void *data)
927 {
928         struct characteristic *chrc = data;
929
930         return (chrc->props & BT_GATT_CHRC_PROP_NOTIFY);
931 }
932
933 static gboolean characteristic_get_mtu(const GDBusPropertyTable *property,
934                                        DBusMessageIter *iter, void *data)
935 {
936         struct characteristic *chrc = data;
937         struct bt_gatt_client *gatt = chrc->service->client->gatt;
938         struct bt_att *att;
939         uint16_t mtu;
940
941         att = bt_gatt_client_get_att(gatt);
942         mtu = att ? bt_att_get_mtu(att) : BT_ATT_DEFAULT_LE_MTU;
943
944         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &mtu);
945
946         return TRUE;
947 }
948
949 static gboolean characteristic_mtu_exists(const GDBusPropertyTable *property,
950                                                                 void *data)
951 {
952         struct characteristic *chrc = data;
953
954         return chrc->service->client->gatt ? TRUE : FALSE;
955 }
956
957 static void write_characteristic_cb(struct gatt_db_attribute *attr, int err,
958                                                                 void *user_data)
959 {
960         struct characteristic *chrc = user_data;
961
962         if (err)
963                 return;
964
965         g_dbus_emit_property_changed_full(btd_get_dbus_connection(),
966                                 chrc->path, GATT_CHARACTERISTIC_IFACE,
967                                 "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH);
968
969 }
970
971 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
972 static void notify_characteristic_cb(struct gatt_db_attribute *attr, int err,
973                                                                 void *user_data)
974 {
975         if (err) {
976                 error("Failed to notify_characteristic_cb : %d", err);
977                 return;
978         }
979 }
980 #endif
981
982 static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
983                                         uint16_t length, void *user_data)
984 {
985         struct async_dbus_op *op = user_data;
986         struct characteristic *chrc = op->data;
987
988         if (!success)
989                 goto fail;
990
991         if (!op->offset)
992                 gatt_db_attribute_reset(chrc->attr);
993
994         if (!gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0,
995                                         NULL, write_characteristic_cb, chrc)) {
996                 error("Failed to store attribute");
997                 att_ecode = BT_ATT_ERROR_UNLIKELY;
998                 goto fail;
999         }
1000
1001         /* Read the stored data from db */
1002         if (!gatt_db_attribute_read(chrc->attr, op->offset, 0, NULL, read_op_cb,
1003                                                                         op)) {
1004                 error("Failed to read database");
1005                 att_ecode = BT_ATT_ERROR_UNLIKELY;
1006                 goto fail;
1007         }
1008
1009         chrc->read_op = NULL;
1010
1011         return;
1012
1013 fail:
1014         async_dbus_op_reply(op, att_ecode, NULL, 0);
1015         chrc->read_op = NULL;
1016 }
1017
1018 static DBusMessage *characteristic_read_value(DBusConnection *conn,
1019                                         DBusMessage *msg, void *user_data)
1020 {
1021         struct characteristic *chrc = user_data;
1022         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1023         DBusMessageIter iter;
1024         uint16_t offset = 0;
1025
1026         if (!gatt)
1027                 return btd_error_failed(msg, "Not connected");
1028
1029         dbus_message_iter_init(msg, &iter);
1030
1031         if (parse_options(&iter, &offset, NULL))
1032                 return btd_error_invalid_args(msg);
1033
1034         if (chrc->read_op) {
1035                 if (chrc->read_op->offset != offset)
1036                         return btd_error_in_progress(msg);
1037                 queue_push_tail(chrc->read_op->msgs, dbus_message_ref(msg));
1038                 return NULL;
1039         }
1040
1041         chrc->read_op = read_value(gatt, msg, chrc->value_handle, offset,
1042                                                         chrc_read_cb, chrc);
1043         if (!chrc->read_op)
1044                 return btd_error_failed(msg, "Failed to send read request");
1045
1046         return NULL;
1047 }
1048
1049 static bool chrc_write_complete(void *data)
1050 {
1051         struct characteristic *chrc = data;
1052
1053         chrc->write_op = NULL;
1054
1055         /*
1056          * The characteristic might have been unregistered during the read.
1057          * Return failure.
1058          */
1059         return !!chrc->service;
1060 }
1061
1062 static DBusMessage *characteristic_write_value(DBusConnection *conn,
1063                                         DBusMessage *msg, void *user_data)
1064 {
1065         struct characteristic *chrc = user_data;
1066         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1067         DBusMessageIter iter;
1068         uint8_t *value = NULL;
1069         int value_len = 0;
1070         bool supported = false;
1071         uint16_t offset = 0;
1072         const char *type = NULL;
1073
1074         if (!gatt)
1075                 return btd_error_failed(msg, "Not connected");
1076
1077         if (chrc->write_io)
1078                 return btd_error_not_permitted(msg, "Write acquired");
1079
1080         if (chrc->write_op)
1081                 return btd_error_in_progress(msg);
1082
1083         dbus_message_iter_init(msg, &iter);
1084
1085         if (parse_value_arg(&iter, &value, &value_len))
1086                 return btd_error_invalid_args(msg);
1087
1088         dbus_message_iter_next(&iter);
1089
1090         if (parse_options(&iter, &offset, &type))
1091                 return btd_error_invalid_args(msg);
1092
1093         /*
1094          * Decide which write to use based on characteristic properties. For now
1095          * we don't perform signed writes since gatt-client doesn't support them
1096          * and the user can always encrypt the through pairing. The procedure to
1097          * use is determined based on the following priority:
1098          *
1099          *   * "reliable-write" property set -> reliable long-write.
1100          *   * "write" property set -> write request.
1101          *     - If value is larger than MTU - 3: long-write
1102          *   * "write-without-response" property set -> write command.
1103          */
1104 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
1105         if ((!type && (chrc->ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE))
1106                         || (type && !strcasecmp(type, "reliable"))) {
1107                 supported = true;
1108                 chrc->write_op = start_long_write(msg, chrc->value_handle, gatt,
1109                                                 true, value, value_len, offset,
1110                                                 chrc, chrc_write_complete);
1111                 if (chrc->write_op)
1112                         return NULL;
1113         }
1114 #endif
1115
1116         if ((!type && chrc->props & BT_GATT_CHRC_PROP_WRITE) ||
1117                         (type && !strcasecmp(type, "request"))) {
1118                 uint16_t mtu;
1119
1120                 supported = true;
1121                 mtu = bt_gatt_client_get_mtu(gatt);
1122                 if (!mtu)
1123                         return btd_error_failed(msg, "No ATT transport");
1124
1125                 if (value_len <= mtu - 3 && !offset)
1126                         chrc->write_op = start_write_request(msg,
1127                                                 chrc->value_handle,
1128                                                 gatt, value, value_len,
1129                                                 chrc, chrc_write_complete);
1130                 else
1131                         chrc->write_op = start_long_write(msg,
1132                                                 chrc->value_handle, gatt,
1133                                                 false, value, value_len, offset,
1134                                                 chrc, chrc_write_complete);
1135
1136                 if (chrc->write_op)
1137                         return NULL;
1138         }
1139
1140         if ((type && strcasecmp(type, "command")) || offset || (!type &&
1141                         !(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP)))
1142                 goto fail;
1143
1144         supported = true;
1145
1146         if (bt_gatt_client_write_without_response(gatt,
1147                                         chrc->value_handle,
1148                                         chrc->props & BT_GATT_CHRC_PROP_AUTH,
1149                                         value, value_len))
1150                 return dbus_message_new_method_return(msg);
1151
1152 fail:
1153         if (supported)
1154                 return btd_error_failed(msg, "Failed to initiate write");
1155
1156         return btd_error_not_supported(msg);
1157 }
1158
1159 static bool sock_read(struct io *io, void *user_data)
1160 {
1161         struct characteristic *chrc = user_data;
1162         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1163         struct msghdr msg;
1164         uint8_t buf[512];
1165         struct iovec iov;
1166         int fd = io_get_fd(io);
1167         ssize_t bytes_read;
1168
1169         iov.iov_base = buf;
1170         iov.iov_len = sizeof(buf);
1171
1172         memset(&msg, 0, sizeof(msg));
1173         msg.msg_iov = &iov;
1174         msg.msg_iovlen = 1;
1175
1176         bytes_read = recvmsg(fd, &msg, MSG_DONTWAIT);
1177         if (bytes_read < 0) {
1178                 error("recvmsg: %s", strerror(errno));
1179                 return false;
1180         }
1181
1182         if (!gatt || bytes_read == 0)
1183                 return false;
1184
1185         bt_gatt_client_write_without_response(gatt, chrc->value_handle,
1186                                         chrc->props & BT_GATT_CHRC_PROP_AUTH,
1187                                         buf, bytes_read);
1188
1189         return true;
1190 }
1191
1192 static void sock_io_destroy(struct sock_io *io)
1193 {
1194         if (io->destroy)
1195                 io->destroy(io->data);
1196
1197         if (io->msg)
1198                 dbus_message_unref(io->msg);
1199
1200         io_destroy(io->io);
1201         free(io);
1202 }
1203
1204 static void destroy_sock(struct characteristic *chrc,
1205                                                         struct io *io)
1206 {
1207         queue_remove(chrc->service->client->ios, io);
1208
1209         if (chrc->write_io && io == chrc->write_io->io) {
1210                 sock_io_destroy(chrc->write_io);
1211                 chrc->write_io = NULL;
1212                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1213                                                 chrc->path,
1214                                                 GATT_CHARACTERISTIC_IFACE,
1215                                                 "WriteAcquired");
1216         } else if (chrc->notify_io) {
1217                 sock_io_destroy(chrc->notify_io);
1218                 chrc->notify_io = NULL;
1219                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1220                                                 chrc->path,
1221                                                 GATT_CHARACTERISTIC_IFACE,
1222                                                 "NotifyAcquired");
1223         }
1224 }
1225
1226 static bool sock_hup(struct io *io, void *user_data)
1227 {
1228         struct characteristic *chrc = user_data;
1229
1230         DBG("%s: io %p", chrc->path, io);
1231
1232         destroy_sock(chrc, io);
1233
1234         return false;
1235 }
1236
1237 static DBusMessage *create_sock(struct characteristic *chrc,
1238                                                 DBusMessage *msg)
1239 {
1240         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1241         int fds[2];
1242         struct io *io;
1243         bool dir;
1244         uint16_t mtu;
1245         DBusMessage *reply;
1246
1247         if (!gatt || !bt_gatt_client_is_ready(gatt))
1248                 return btd_error_failed(msg, "Not connected");
1249
1250         if (socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC,
1251                                                                 0, fds) < 0)
1252                 return btd_error_failed(msg, strerror(errno));
1253
1254         dir = dbus_message_has_member(msg, "AcquireWrite");
1255
1256         io = io_new(fds[!dir]);
1257         if (!io) {
1258                 close(fds[0]);
1259                 close(fds[1]);
1260                 return btd_error_failed(msg, strerror(EIO));
1261         }
1262
1263         io_set_close_on_destroy(io, true);
1264
1265         if (!io_set_read_handler(io, sock_read, chrc, NULL))
1266                 goto fail;
1267
1268         if (!io_set_disconnect_handler(io, sock_hup, chrc, NULL))
1269                 goto fail;
1270
1271         mtu = bt_gatt_client_get_mtu(gatt);
1272
1273         reply = g_dbus_create_reply(msg, DBUS_TYPE_UNIX_FD, &fds[dir],
1274                                         DBUS_TYPE_UINT16, &mtu,
1275                                         DBUS_TYPE_INVALID);
1276
1277         close(fds[dir]);
1278
1279         if (dir) {
1280                 chrc->write_io->io = io;
1281                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1282                                                 chrc->path,
1283                                                 GATT_CHARACTERISTIC_IFACE,
1284                                                 "WriteAcquired");
1285         } else {
1286                 chrc->notify_io->io = io;
1287                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1288                                                 chrc->path,
1289                                                 GATT_CHARACTERISTIC_IFACE,
1290                                                 "NotifyAcquired");
1291         }
1292
1293         queue_push_tail(chrc->service->client->ios, io);
1294
1295         DBG("%s: sender %s io %p", dbus_message_get_member(msg),
1296                                         dbus_message_get_sender(msg), io);
1297
1298         return reply;
1299
1300 fail:
1301         io_destroy(io);
1302         close(fds[dir]);
1303         return btd_error_failed(msg, strerror(EIO));
1304 }
1305
1306 static void characteristic_ready(bool success, uint8_t ecode, void *user_data)
1307 {
1308         struct characteristic *chrc = user_data;
1309         DBusMessage *reply;
1310
1311         chrc->ready_id = 0;
1312
1313         if (chrc->write_io && chrc->write_io->msg) {
1314                 reply = create_sock(chrc, chrc->write_io->msg);
1315
1316                 g_dbus_send_message(btd_get_dbus_connection(), reply);
1317
1318                 dbus_message_unref(chrc->write_io->msg);
1319                 chrc->write_io->msg = NULL;
1320         }
1321
1322         if (chrc->notify_io && chrc->notify_io->msg) {
1323                 reply = create_sock(chrc, chrc->notify_io->msg);
1324
1325                 g_dbus_send_message(btd_get_dbus_connection(), reply);
1326
1327                 dbus_message_unref(chrc->notify_io->msg);
1328                 chrc->notify_io->msg = NULL;
1329         }
1330 }
1331
1332 static DBusMessage *characteristic_acquire_write(DBusConnection *conn,
1333                                         DBusMessage *msg, void *user_data)
1334 {
1335         struct characteristic *chrc = user_data;
1336         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1337
1338         if (!gatt)
1339                 return btd_error_failed(msg, "Not connected");
1340
1341         if (chrc->write_io)
1342                 return btd_error_not_permitted(msg, "Write acquired");
1343
1344         if (!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP))
1345                 return btd_error_not_supported(msg);
1346
1347         chrc->write_io = new0(struct sock_io, 1);
1348
1349         if (!bt_gatt_client_is_ready(gatt)) {
1350                 /* GATT not ready, wait until it becomes ready */
1351                 if (!chrc->ready_id)
1352                         chrc->ready_id = bt_gatt_client_ready_register(gatt,
1353                                                         characteristic_ready,
1354                                                         chrc, NULL);
1355                 chrc->write_io->msg = dbus_message_ref(msg);
1356                 return NULL;
1357         }
1358
1359         return create_sock(chrc, msg);
1360 }
1361
1362 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1363 static DBusMessage *characteristic_write_value_by_type(DBusConnection *conn,
1364                                         DBusMessage *msg, void *user_data)
1365 {
1366         struct characteristic *chrc = user_data;
1367         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1368         DBusMessageIter iter;
1369         uint8_t *value = NULL;
1370         int value_len = 0;
1371         bool supported = false;
1372         uint8_t write_type = 0;
1373         uint16_t offset = 0;
1374
1375         if (!gatt)
1376                 return btd_error_failed(msg, "Not connected");
1377
1378         if (chrc->write_op)
1379                 return btd_error_in_progress(msg);
1380
1381         dbus_message_iter_init(msg, &iter);
1382
1383         if (parse_type_value_arg(&iter, &write_type, &value, &value_len))
1384                 return btd_error_invalid_args(msg);
1385
1386         if (parse_options(&iter, &offset,NULL))
1387                 return btd_error_invalid_args(msg);
1388
1389         if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_WRITE) {
1390                 uint16_t mtu;
1391
1392                 supported = true;
1393                 mtu = bt_gatt_client_get_mtu(gatt);
1394                 if (!mtu)
1395                         return btd_error_failed(msg, "No ATT transport");
1396
1397                 if (value_len <= mtu - 3 && !offset)
1398                         chrc->write_op = start_write_request(msg,
1399                                                 chrc->value_handle,
1400                                                 gatt, value, value_len,
1401                                                 chrc, chrc_write_complete);
1402                 else
1403                         chrc->write_op = start_long_write(msg,
1404                                                 chrc->value_handle, gatt,
1405                                                 false, value, value_len, offset,
1406                                                 chrc, chrc_write_complete);
1407
1408                 if (chrc->write_op)
1409                         return NULL;
1410         } else if ((write_type & chrc->props) ==
1411                         BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) {
1412                 supported = true;
1413                 chrc->write_op = start_write_cmd(msg, chrc->value_handle, gatt,
1414                                                  false, value, value_len,
1415                                                  chrc, chrc_write_complete);
1416                 if (chrc->write_op)
1417                         return NULL;
1418         } else if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_AUTH) {
1419                 supported = true;
1420                 chrc->write_op = start_write_cmd(msg, chrc->value_handle, gatt,
1421                                                  true, value, value_len,
1422                                                  chrc, chrc_write_complete);
1423                 if (chrc->write_op)
1424                         return NULL;
1425         }
1426
1427         if (supported)
1428                 return btd_error_failed(msg, "Failed to initiate write");
1429
1430         return btd_error_not_supported(msg);
1431 }
1432 #endif
1433
1434 struct notify_client {
1435         struct characteristic *chrc;
1436         int ref_count;
1437         char *owner;
1438         guint watch;
1439         unsigned int notify_id;
1440 };
1441
1442 static void notify_client_free(struct notify_client *client)
1443 {
1444         DBG("owner %s", client->owner);
1445
1446         g_dbus_remove_watch(btd_get_dbus_connection(), client->watch);
1447         bt_gatt_client_unregister_notify(client->chrc->service->client->gatt,
1448                                                         client->notify_id);
1449         free(client->owner);
1450         free(client);
1451 }
1452
1453 static void notify_client_unref(void *data)
1454 {
1455         struct notify_client *client = data;
1456
1457         DBG("owner %s", client->owner);
1458
1459         if (__sync_sub_and_fetch(&client->ref_count, 1))
1460                 return;
1461
1462         notify_client_free(client);
1463 }
1464
1465 static struct notify_client *notify_client_ref(struct notify_client *client)
1466 {
1467         DBG("owner %s", client->owner);
1468
1469         __sync_fetch_and_add(&client->ref_count, 1);
1470
1471         return client;
1472 }
1473
1474 static bool match_notifying(const void *a, const void *b)
1475 {
1476         const struct notify_client *client = a;
1477
1478         return !!client->notify_id;
1479 }
1480
1481 static void update_notifying(struct characteristic *chrc)
1482 {
1483         if (!chrc->notifying)
1484                 return;
1485
1486         if (queue_find(chrc->notify_clients, match_notifying, NULL))
1487                 return;
1488
1489         chrc->notifying = false;
1490
1491         g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
1492                                                 GATT_CHARACTERISTIC_IFACE,
1493                                                 "Notifying");
1494 }
1495
1496 static void notify_client_disconnect(DBusConnection *conn, void *user_data)
1497 {
1498         struct notify_client *client = user_data;
1499         struct characteristic *chrc = client->chrc;
1500
1501         DBG("owner %s", client->owner);
1502
1503         queue_remove(chrc->notify_clients, client);
1504         queue_remove(chrc->service->client->all_notify_clients, client);
1505
1506         update_notifying(chrc);
1507
1508         notify_client_unref(client);
1509 }
1510
1511 static struct notify_client *notify_client_create(struct characteristic *chrc,
1512                                                         const char *owner)
1513 {
1514         struct notify_client *client;
1515
1516         client = new0(struct notify_client, 1);
1517         client->chrc = chrc;
1518         client->owner = strdup(owner);
1519         if (!client->owner) {
1520                 free(client);
1521                 return NULL;
1522         }
1523
1524         client->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
1525                                                 owner, notify_client_disconnect,
1526                                                 client, NULL);
1527         if (!client->watch) {
1528                 free(client->owner);
1529                 free(client);
1530                 return NULL;
1531         }
1532
1533         return notify_client_ref(client);
1534 }
1535
1536 static bool match_notify_sender(const void *a, const void *b)
1537 {
1538         const struct notify_client *client = a;
1539         const char *sender = b;
1540
1541         return strcmp(client->owner, sender) == 0;
1542 }
1543
1544 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1545 void gatt_characteristic_value_changed(struct notify_client *client, const uint8_t *data, uint16_t data_len, void *user_data)
1546 {
1547         struct characteristic *chrc = user_data;
1548         char *chrc_path = strdup(chrc->path);
1549         dbus_int32_t result = 0;
1550
1551         g_dbus_emit_signal_to_dest(btd_get_dbus_connection(),
1552                 client->owner, chrc_path,
1553                 GATT_CHARACTERISTIC_IFACE, "GattValueChanged",
1554                 DBUS_TYPE_INT32, &result,
1555                 DBUS_TYPE_STRING, &chrc_path,
1556                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, data_len,
1557                 DBUS_TYPE_INVALID);
1558
1559         if (chrc_path)
1560                 free(chrc_path);
1561
1562 }
1563 #endif
1564
1565 static void notify_cb(uint16_t value_handle, const uint8_t *value,
1566                                         uint16_t length, void *user_data)
1567 {
1568         struct async_dbus_op *op = user_data;
1569         struct notify_client *client = op->data;
1570         struct characteristic *chrc = client->chrc;
1571
1572         /*
1573          * Even if the value didn't change, we want to send a PropertiesChanged
1574          * signal so that we propagate the notification/indication to
1575          * applications.
1576          */
1577         gatt_db_attribute_reset(chrc->attr);
1578 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1579         gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
1580                                                 notify_characteristic_cb, chrc);
1581
1582         gatt_characteristic_value_changed(client, value, length, chrc);
1583 #else
1584         gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
1585                                                 write_characteristic_cb, chrc);
1586 #endif
1587 }
1588
1589 static void create_notify_reply(struct async_dbus_op *op, bool success,
1590                                                         uint8_t att_ecode)
1591 {
1592         int err;
1593
1594         if (success)
1595                 err = 0;
1596         else
1597                 err = att_ecode ? att_ecode : -ENOENT;
1598
1599         async_dbus_op_reply(op, err, NULL, -1);
1600 }
1601
1602 static void register_notify_cb(uint16_t att_ecode, void *user_data)
1603 {
1604         struct async_dbus_op *op = user_data;
1605         struct notify_client *client = op->data;
1606         struct characteristic *chrc = client->chrc;
1607
1608         if (att_ecode) {
1609                 queue_remove(chrc->notify_clients, client);
1610                 queue_remove(chrc->service->client->all_notify_clients, client);
1611                 notify_client_free(client);
1612
1613                 create_notify_reply(op, false, att_ecode);
1614
1615                 return;
1616         }
1617
1618         if (!chrc->notifying) {
1619                 chrc->notifying = true;
1620                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1621                                         chrc->path, GATT_CHARACTERISTIC_IFACE,
1622                                         "Notifying");
1623         }
1624
1625         create_notify_reply(op, true, 0);
1626 }
1627
1628 static void notify_io_cb(uint16_t value_handle, const uint8_t *value,
1629                                         uint16_t length, void *user_data)
1630 {
1631         struct msghdr msg;
1632         struct iovec iov;
1633         struct notify_client *client = user_data;
1634         struct characteristic *chrc = client->chrc;
1635         int err;
1636
1637         /* Drop notification if the pipe is not ready */
1638         if (!chrc->notify_io ||  !chrc->notify_io->io)
1639                 return;
1640
1641         iov.iov_base = (void *) value;
1642         iov.iov_len = length;
1643
1644         memset(&msg, 0, sizeof(msg));
1645         msg.msg_iov = &iov;
1646         msg.msg_iovlen = 1;
1647
1648         err = sendmsg(io_get_fd(chrc->notify_io->io), &msg, MSG_NOSIGNAL);
1649         if (err < 0)
1650                 error("sendmsg: %s", strerror(errno));
1651 }
1652
1653 static void register_notify_io_cb(uint16_t att_ecode, void *user_data)
1654 {
1655         struct notify_client *client = user_data;
1656         struct characteristic *chrc = client->chrc;
1657         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1658
1659         if (att_ecode) {
1660                 queue_remove(chrc->notify_clients, client);
1661                 notify_client_free(client);
1662                 return;
1663         }
1664
1665         if (!bt_gatt_client_is_ready(gatt)) {
1666                 if (!chrc->ready_id)
1667                         chrc->ready_id = bt_gatt_client_ready_register(gatt,
1668                                                         characteristic_ready,
1669                                                         chrc, NULL);
1670                 return;
1671         }
1672
1673         characteristic_ready(true, 0, chrc);
1674 }
1675
1676 static void notify_io_destroy(void *data)
1677 {
1678         struct notify_client *client = data;
1679
1680         if (queue_remove(client->chrc->notify_clients, client))
1681                 notify_client_unref(client);
1682 }
1683
1684 static DBusMessage *characteristic_acquire_notify(DBusConnection *conn,
1685                                         DBusMessage *msg, void *user_data)
1686 {
1687         struct characteristic *chrc = user_data;
1688         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1689         const char *sender = dbus_message_get_sender(msg);
1690         struct notify_client *client;
1691
1692         if (!gatt)
1693                 return btd_error_failed(msg, "Not connected");
1694
1695         if (chrc->notify_io)
1696                 return btd_error_not_permitted(msg, "Notify acquired");
1697
1698         /* Each client can only have one active notify session. */
1699         if (!queue_isempty(chrc->notify_clients))
1700                 return btd_error_in_progress(msg);
1701
1702         if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY))
1703                 return btd_error_not_supported(msg);
1704
1705         client = notify_client_create(chrc, sender);
1706         if (!client)
1707                 return btd_error_failed(msg, "Failed allocate notify session");
1708
1709 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1710         chrc->notify_io = new0(struct sock_io, 1);
1711         chrc->notify_io->data = client;
1712         chrc->notify_io->msg = dbus_message_ref(msg);
1713         chrc->notify_io->destroy = notify_io_destroy;
1714 #endif
1715         client->notify_id = bt_gatt_client_register_notify(gatt,
1716                                                 chrc->value_handle,
1717                                                 register_notify_io_cb,
1718                                                 notify_io_cb,
1719                                                 client, NULL);
1720         if (!client->notify_id) {
1721                 notify_client_unref(client);
1722 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1723                 dbus_message_unref(chrc->notify_io->msg);
1724                 g_free(chrc->notify_io);
1725                 chrc->notify_io = NULL;
1726 #endif
1727                 return btd_error_failed(msg, "Failed to subscribe");
1728         }
1729
1730         queue_push_tail(chrc->notify_clients, client);
1731
1732 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
1733         chrc->notify_io = new0(struct sock_io, 1);
1734         chrc->notify_io->data = client;
1735         chrc->notify_io->msg = dbus_message_ref(msg);
1736         chrc->notify_io->destroy = notify_io_destroy;
1737 #endif
1738
1739         return NULL;
1740 }
1741
1742 static DBusMessage *characteristic_start_notify(DBusConnection *conn,
1743                                         DBusMessage *msg, void *user_data)
1744 {
1745         struct characteristic *chrc = user_data;
1746         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1747         const char *sender = dbus_message_get_sender(msg);
1748         struct async_dbus_op *op;
1749         struct notify_client *client;
1750         struct btd_device *device = chrc->service->client->device;
1751
1752         if (device_is_disconnecting(device)) {
1753                 error("Device is disconnecting. StartNotify is not allowed.");
1754                 return btd_error_not_connected(msg);
1755         }
1756
1757         if (chrc->notify_io)
1758                 return btd_error_not_permitted(msg, "Notify acquired");
1759
1760         if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
1761                                 chrc->props & BT_GATT_CHRC_PROP_INDICATE))
1762                 return btd_error_not_supported(msg);
1763
1764         /* Each client can only have one active notify session. */
1765         client = queue_find(chrc->notify_clients, match_notify_sender, sender);
1766         if (client)
1767                 return client->notify_id ?
1768                                 g_dbus_create_reply(msg, DBUS_TYPE_INVALID) :
1769                                 btd_error_in_progress(msg);
1770
1771         client = notify_client_create(chrc, sender);
1772         if (!client)
1773                 return btd_error_failed(msg, "Failed allocate notify session");
1774
1775         queue_push_tail(chrc->notify_clients, client);
1776         queue_push_tail(chrc->service->client->all_notify_clients, client);
1777
1778         /*
1779          * If the device is currently not connected, return success. We will
1780          * automatically try and register all clients when a GATT client becomes
1781          * ready.
1782          */
1783         if (!gatt) {
1784                 DBusMessage *reply;
1785
1786                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1787                 if (reply)
1788                         return reply;
1789
1790                 /*
1791                  * Clean up and respond with an error instead of timing out to
1792                  * avoid any ambiguities.
1793                  */
1794                 error("Failed to construct D-Bus message reply");
1795                 goto fail;
1796         }
1797
1798         op = async_dbus_op_new(msg, client);
1799
1800         client->notify_id = bt_gatt_client_register_notify(gatt,
1801                                                 chrc->value_handle,
1802                                                 register_notify_cb, notify_cb,
1803                                                 op, async_dbus_op_free);
1804         if (client->notify_id)
1805                 return NULL;
1806
1807         async_dbus_op_free(op);
1808
1809 fail:
1810         queue_remove(chrc->notify_clients, client);
1811         queue_remove(chrc->service->client->all_notify_clients, client);
1812
1813         /* Directly free the client */
1814         notify_client_free(client);
1815
1816         return btd_error_failed(msg, "Failed to register notify session");
1817 }
1818
1819 static DBusMessage *characteristic_stop_notify(DBusConnection *conn,
1820                                         DBusMessage *msg, void *user_data)
1821 {
1822         struct characteristic *chrc = user_data;
1823         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1824         const char *sender = dbus_message_get_sender(msg);
1825         struct notify_client *client;
1826
1827         if (chrc->notify_io) {
1828                 destroy_sock(chrc, chrc->notify_io->io);
1829                 return dbus_message_new_method_return(msg);
1830         }
1831
1832
1833         client = queue_remove_if(chrc->notify_clients, match_notify_sender,
1834                                                         (void *) sender);
1835         if (!client)
1836                 return btd_error_failed(msg, "No notify session started");
1837
1838         queue_remove(chrc->service->client->all_notify_clients, client);
1839         bt_gatt_client_unregister_notify(gatt, client->notify_id);
1840         update_notifying(chrc);
1841
1842         notify_client_unref(client);
1843
1844         return dbus_message_new_method_return(msg);
1845 }
1846
1847 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1848 static void append_desc_path(void *data, void *user_data)
1849 {
1850         struct descriptor *desc = data;
1851         DBusMessageIter *array = user_data;
1852
1853         dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH,
1854                                                                 &desc->path);
1855 }
1856
1857 static gboolean characteristic_get_descriptors(
1858                                         const GDBusPropertyTable *property,
1859                                         DBusMessageIter *iter, void *data)
1860 {
1861         struct characteristic *chrc = data;
1862         DBusMessageIter array;
1863
1864         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "o", &array);
1865
1866         queue_foreach(chrc->descs, append_desc_path, &array);
1867
1868         dbus_message_iter_close_container(iter, &array);
1869
1870         return TRUE;
1871 }
1872 #endif
1873
1874 static const GDBusPropertyTable characteristic_properties[] = {
1875         { "UUID", "s", characteristic_get_uuid, NULL, NULL },
1876         { "Service", "o", characteristic_get_service, NULL, NULL },
1877         { "Value", "ay", characteristic_get_value, NULL,
1878                                         characteristic_value_exists },
1879 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1880         { "ChangedValue", "ay", characteristic_get_value, NULL,
1881                                         characteristic_value_exists },
1882 #endif
1883         { "Notifying", "b", characteristic_get_notifying, NULL,
1884                                         characteristic_notifying_exists },
1885         { "Flags", "as", characteristic_get_flags, NULL, NULL },
1886         { "WriteAcquired", "b", characteristic_get_write_acquired, NULL,
1887                                 characteristic_write_acquired_exists },
1888         { "NotifyAcquired", "b", characteristic_get_notify_acquired, NULL,
1889                                 characteristic_notify_acquired_exists },
1890         { "MTU", "q", characteristic_get_mtu, NULL, characteristic_mtu_exists },
1891 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1892         { "Descriptors", "ao", characteristic_get_descriptors },
1893 #endif
1894         { }
1895 };
1896
1897 static const GDBusMethodTable characteristic_methods[] = {
1898         { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
1899                                         GDBUS_ARGS({ "value", "ay" }),
1900                                         characteristic_read_value) },
1901         { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
1902                                                 { "options", "a{sv}" }),
1903                                         NULL,
1904                                         characteristic_write_value) },
1905         { GDBUS_ASYNC_METHOD("AcquireWrite",
1906                                         GDBUS_ARGS({ "options", "a{sv}" }),
1907                                         GDBUS_ARGS({ "fd", "h" },
1908                                                 { "mtu", "q" }),
1909                                         characteristic_acquire_write) },
1910         { GDBUS_ASYNC_METHOD("AcquireNotify",
1911                                         GDBUS_ARGS({ "options", "a{sv}" }),
1912                                         GDBUS_ARGS({ "fd", "h" },
1913                                                 { "mtu", "q" }),
1914                                         characteristic_acquire_notify) },
1915 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1916         { GDBUS_ASYNC_METHOD("WriteValuebyType",
1917                                         GDBUS_ARGS({ "type", "y" }, { "value", "ay" },
1918                                                 { "options", "a{sv}" }),
1919                                         NULL,
1920                                         characteristic_write_value_by_type) },
1921 #endif
1922         { GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL,
1923                                         characteristic_start_notify) },
1924         { GDBUS_METHOD("StopNotify", NULL, NULL,
1925                                         characteristic_stop_notify) },
1926         { }
1927 };
1928
1929 static void remove_client(void *data)
1930 {
1931         struct notify_client *ntfy_client = data;
1932         struct btd_gatt_client *client = ntfy_client->chrc->service->client;
1933
1934         queue_remove(client->all_notify_clients, ntfy_client);
1935
1936         notify_client_unref(ntfy_client);
1937 }
1938
1939 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1940 static const GDBusSignalTable service_signals[] = {
1941         { GDBUS_SIGNAL("GattServiceAdded",
1942                         GDBUS_ARGS({ "Service Path","s"})) },
1943         { }
1944 };
1945 static const GDBusSignalTable characteristic_signals[] = {
1946         { GDBUS_SIGNAL("GattValueChanged",
1947                         GDBUS_ARGS({ "Result", "i"},
1948                                         { "Characteristic Path","s"},
1949                                         { "GattData", "ay"})) },
1950         { }
1951 };
1952 #endif
1953
1954 static void characteristic_free(void *data)
1955 {
1956         struct characteristic *chrc = data;
1957         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1958         struct bt_att *att;
1959
1960         /* List should be empty here */
1961         queue_destroy(chrc->descs, NULL);
1962
1963         if (chrc->write_io) {
1964                 queue_remove(chrc->service->client->ios, chrc->write_io->io);
1965                 sock_io_destroy(chrc->write_io);
1966         }
1967
1968         if (chrc->notify_io) {
1969                 queue_remove(chrc->service->client->ios, chrc->notify_io->io);
1970                 sock_io_destroy(chrc->notify_io);
1971         }
1972
1973         queue_destroy(chrc->notify_clients, remove_client);
1974
1975         att = bt_gatt_client_get_att(gatt);
1976         if (att)
1977                 bt_att_unregister_exchange(att, chrc->exchange_id);
1978
1979         g_free(chrc->path);
1980         free(chrc);
1981 }
1982
1983 static void att_exchange(uint16_t mtu, void *user_data)
1984 {
1985         struct characteristic *chrc = user_data;
1986
1987         g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
1988                                         GATT_CHARACTERISTIC_IFACE, "MTU");
1989 }
1990
1991 static struct characteristic *characteristic_create(
1992                                                 struct gatt_db_attribute *attr,
1993                                                 struct service *service)
1994 {
1995         struct characteristic *chrc;
1996         struct bt_gatt_client *gatt = service->client->gatt;
1997         struct bt_att *att;
1998         bt_uuid_t uuid;
1999
2000         chrc = new0(struct characteristic, 1);
2001         chrc->descs = queue_new();
2002         chrc->notify_clients = queue_new();
2003         chrc->service = service;
2004
2005 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
2006         gatt_db_attribute_get_char_data(attr, &chrc->handle,
2007                                                         &chrc->value_handle,
2008                                                         &chrc->props,
2009                                                         &chrc->ext_props,
2010                                                         &uuid);
2011 #else
2012         if (!gatt_db_attribute_get_char_data(attr, &chrc->handle,
2013                                                         &chrc->value_handle,
2014                                                         &chrc->props,
2015                                                         &chrc->ext_props,
2016                                                         &uuid)) {
2017                 queue_destroy(chrc->descs, NULL);
2018                 queue_destroy(chrc->notify_clients, NULL);
2019                 free(chrc);
2020                 return NULL;
2021         }
2022 #endif
2023
2024         chrc->attr = gatt_db_get_attribute(service->client->db,
2025                                                         chrc->value_handle);
2026         if (!chrc->attr) {
2027                 error("Attribute 0x%04x not found", chrc->value_handle);
2028                 characteristic_free(chrc);
2029                 return NULL;
2030         }
2031
2032         bt_uuid_to_uuid128(&uuid, &chrc->uuid);
2033
2034         chrc->path = g_strdup_printf("%s/char%04x", service->path,
2035                                                                 chrc->handle);
2036
2037         if (!g_dbus_register_interface(btd_get_dbus_connection(), chrc->path,
2038                                                 GATT_CHARACTERISTIC_IFACE,
2039 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2040                                                 characteristic_methods, characteristic_signals,
2041 #else
2042                                                 characteristic_methods, NULL,
2043 #endif
2044                                                 characteristic_properties,
2045                                                 chrc, characteristic_free)) {
2046                 error("Unable to register GATT characteristic with handle "
2047                                                         "0x%04x", chrc->handle);
2048                 characteristic_free(chrc);
2049
2050                 return NULL;
2051         }
2052
2053         att = bt_gatt_client_get_att(gatt);
2054         if (att)
2055                 chrc->exchange_id = bt_att_register_exchange(att, att_exchange,
2056                                                                 chrc, NULL);
2057
2058         DBG("Exported GATT characteristic: %s", chrc->path);
2059
2060         return chrc;
2061 }
2062
2063 static void unregister_characteristic(void *data)
2064 {
2065         struct characteristic *chrc = data;
2066         struct bt_gatt_client *gatt = chrc->service->client->gatt;
2067
2068         DBG("Removing GATT characteristic: %s", chrc->path);
2069
2070         if (chrc->read_op)
2071                 bt_gatt_client_cancel(gatt, chrc->read_op->id);
2072
2073         if (chrc->write_op)
2074                 bt_gatt_client_cancel(gatt, chrc->write_op->id);
2075
2076         queue_remove_all(chrc->descs, NULL, NULL, unregister_descriptor);
2077
2078         g_dbus_unregister_interface(btd_get_dbus_connection(), chrc->path,
2079                                                 GATT_CHARACTERISTIC_IFACE);
2080 }
2081
2082 static gboolean service_get_uuid(const GDBusPropertyTable *property,
2083                                         DBusMessageIter *iter, void *data)
2084 {
2085         char uuid[MAX_LEN_UUID_STR + 1];
2086         const char *ptr = uuid;
2087         struct service *service = data;
2088
2089         bt_uuid_to_string(&service->uuid, uuid, sizeof(uuid));
2090         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
2091
2092         return TRUE;
2093 }
2094
2095 static gboolean service_get_device(const GDBusPropertyTable *property,
2096                                         DBusMessageIter *iter, void *data)
2097 {
2098         struct service *service = data;
2099         const char *str = device_get_path(service->client->device);
2100
2101         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &str);
2102
2103         return TRUE;
2104 }
2105
2106 static gboolean service_get_primary(const GDBusPropertyTable *property,
2107                                         DBusMessageIter *iter, void *data)
2108 {
2109         struct service *service = data;
2110         dbus_bool_t primary;
2111
2112         primary = service->primary ? TRUE : FALSE;
2113
2114         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &primary);
2115
2116         return TRUE;
2117 }
2118
2119 static void append_incl_service_path(void *data, void *user_data)
2120 {
2121         struct service *incl_service = data;
2122         DBusMessageIter *array = user_data;
2123
2124         dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH,
2125                                         &incl_service->path);
2126 }
2127
2128 static gboolean service_get_includes(const GDBusPropertyTable *property,
2129                                         DBusMessageIter *iter, void *data)
2130 {
2131         struct service *service = data;
2132         DBusMessageIter array;
2133
2134         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{o}", &array);
2135
2136         queue_foreach(service->incl_services, append_incl_service_path, &array);
2137
2138         dbus_message_iter_close_container(iter, &array);
2139
2140         return TRUE;
2141
2142 }
2143
2144 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2145 static void append_chrc_path(void *data, void *user_data)
2146 {
2147         struct characteristic *chrc = data;
2148         DBusMessageIter *array = user_data;
2149
2150         dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH,
2151                                                                 &chrc->path);
2152 }
2153
2154 static gboolean service_get_characteristics(const GDBusPropertyTable *property,
2155                                         DBusMessageIter *iter, void *data)
2156 {
2157         struct service *service = data;
2158         DBusMessageIter array;
2159
2160         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "o", &array);
2161
2162         if (service->chrcs_ready)
2163                 queue_foreach(service->chrcs, append_chrc_path, &array);
2164
2165         dbus_message_iter_close_container(iter, &array);
2166
2167         return TRUE;
2168 }
2169 #endif
2170
2171 static const GDBusPropertyTable service_properties[] = {
2172         { "UUID", "s", service_get_uuid },
2173         { "Device", "o", service_get_device },
2174         { "Primary", "b", service_get_primary },
2175         { "Includes", "ao", service_get_includes },
2176 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2177         { "Characteristics", "ao", service_get_characteristics },
2178 #endif
2179         { }
2180 };
2181
2182 static void service_free(void *data)
2183 {
2184         struct service *service = data;
2185
2186         queue_destroy(service->chrcs, NULL);  /* List should be empty here */
2187         queue_destroy(service->incl_services, NULL);
2188         g_free(service->path);
2189         free(service);
2190 }
2191
2192 static struct service *service_create(struct gatt_db_attribute *attr,
2193                                                 struct btd_gatt_client *client)
2194 {
2195         struct service *service;
2196         const char *device_path = device_get_path(client->device);
2197         bt_uuid_t uuid;
2198
2199         service = new0(struct service, 1);
2200         service->chrcs = queue_new();
2201         service->incl_services = queue_new();
2202         service->client = client;
2203
2204         gatt_db_attribute_get_service_data(attr, &service->start_handle,
2205                                                         &service->end_handle,
2206                                                         &service->primary,
2207                                                         &uuid);
2208         bt_uuid_to_uuid128(&uuid, &service->uuid);
2209
2210         service->path = g_strdup_printf("%s/service%04x", device_path,
2211                                                         service->start_handle);
2212
2213         if (!g_dbus_register_interface(btd_get_dbus_connection(), service->path,
2214                                                 GATT_SERVICE_IFACE,
2215 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2216                                                 NULL, service_signals,
2217 #else
2218                                                 NULL, NULL,
2219 #endif
2220                                                 service_properties,
2221                                                 service, service_free)) {
2222                 error("Unable to register GATT service with handle 0x%04x for "
2223                                                         "device %s",
2224                                                         service->start_handle,
2225                                                         client->devaddr);
2226                 service_free(service);
2227
2228                 return NULL;
2229         }
2230
2231         DBG("Exported GATT service: %s", service->path);
2232
2233         /* Set service active so we can skip discovering next time */
2234         gatt_db_service_set_active(attr, true);
2235
2236         /* Mark the service as claimed since it going to be exported */
2237         gatt_db_service_set_claimed(attr, true);
2238
2239         return service;
2240 }
2241
2242 static void on_service_removed(void *data, void *user_data)
2243 {
2244         struct service *service = data;
2245         struct service *removed_service = user_data;
2246
2247         if (queue_remove(service->incl_services, removed_service))
2248                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
2249                                                         service->path,
2250                                                         GATT_SERVICE_IFACE,
2251                                                         "Includes");
2252 }
2253
2254 static void unregister_service(void *data)
2255 {
2256         struct service *service = data;
2257         struct btd_gatt_client *client = service->client;
2258
2259         DBG("Removing GATT service: %s", service->path);
2260
2261 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2262         if (service->idle_id)
2263                 g_source_remove(service->idle_id);
2264 #endif
2265
2266         queue_remove_all(service->chrcs, NULL, NULL, unregister_characteristic);
2267         queue_remove_all(service->incl_services, NULL, NULL, NULL);
2268
2269         queue_foreach(client->services, on_service_removed, service);
2270
2271         g_dbus_unregister_interface(btd_get_dbus_connection(), service->path,
2272                                                         GATT_SERVICE_IFACE);
2273 }
2274
2275 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2276 static void notify_service_added(struct service *service)
2277 {
2278         char *svc_path;
2279
2280         if (service == NULL) {
2281                 error("service is NULL");
2282                 return;
2283         }
2284
2285         if (service->path == NULL) {
2286                 error("service->path is NULL");
2287                 return;
2288         }
2289         if (!service->chrcs_ready) {
2290                 error("service is not ready");
2291                 return;
2292         }
2293
2294         svc_path = g_strdup(service->path);
2295
2296         g_dbus_emit_signal(btd_get_dbus_connection(), service->path,
2297                 GATT_SERVICE_IFACE, "GattServiceAdded",
2298                 DBUS_TYPE_STRING, &svc_path,
2299                 DBUS_TYPE_INVALID);
2300
2301         g_free(svc_path);
2302
2303         return;
2304 }
2305
2306 static void notify_chrcs(struct service *service)
2307 {
2308
2309         if (service->chrcs_ready ||
2310                                 !queue_isempty(service->pending_ext_props))
2311                 return;
2312
2313         service->chrcs_ready = true;
2314
2315         g_dbus_emit_property_changed(btd_get_dbus_connection(), service->path,
2316                                                         GATT_SERVICE_IFACE,
2317                                                         "Characteristics");
2318         if (service->primary == true) {
2319                 DBG("Notify Service Added");
2320                 notify_service_added(service);
2321         }
2322 }
2323 #endif
2324
2325 struct export_data {
2326         void *root;
2327         bool failed;
2328 };
2329
2330 static void export_desc(struct gatt_db_attribute *attr, void *user_data)
2331 {
2332         struct descriptor *desc;
2333         struct export_data *data = user_data;
2334         struct characteristic *charac = data->root;
2335
2336         if (data->failed)
2337                 return;
2338
2339         desc = descriptor_create(attr, charac);
2340         if (!desc) {
2341                 data->failed = true;
2342                 return;
2343         }
2344
2345         queue_push_tail(charac->descs, desc);
2346 }
2347
2348 static bool create_descriptors(struct gatt_db_attribute *attr,
2349                                         struct characteristic *charac)
2350 {
2351         struct export_data data;
2352
2353         data.root = charac;
2354         data.failed = false;
2355
2356         gatt_db_service_foreach_desc(attr, export_desc, &data);
2357
2358         return !data.failed;
2359 }
2360
2361 static void export_char(struct gatt_db_attribute *attr, void *user_data)
2362 {
2363         struct characteristic *charac;
2364         struct export_data *data = user_data;
2365         struct service *service = data->root;
2366
2367         if (data->failed)
2368                 return;
2369
2370         charac = characteristic_create(attr, service);
2371         if (!charac)
2372                 goto fail;
2373
2374         if (!create_descriptors(attr, charac)) {
2375                 unregister_characteristic(charac);
2376                 goto fail;
2377         }
2378
2379         queue_push_tail(service->chrcs, charac);
2380
2381 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2382         if (charac->ext_props_handle)
2383                 queue_push_tail(service->pending_ext_props, charac);
2384 #endif
2385
2386         return;
2387
2388 fail:
2389         data->failed = true;
2390 }
2391
2392 static bool create_characteristics(struct gatt_db_attribute *attr,
2393                                                 struct service *service)
2394 {
2395         struct export_data data;
2396
2397         data.root = service;
2398         data.failed = false;
2399
2400         gatt_db_service_foreach_char(attr, export_char, &data);
2401
2402         return !data.failed;
2403 }
2404
2405 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2406 static gboolean set_chrcs_ready(gpointer user_data)
2407 {
2408         struct service *service = user_data;
2409
2410         service->idle_id = 0;
2411         notify_chrcs(service);
2412
2413         return FALSE;
2414 }
2415 #endif
2416 static void export_service(struct gatt_db_attribute *attr, void *user_data)
2417 {
2418         struct btd_gatt_client *client = user_data;
2419         struct service *service;
2420
2421         if (gatt_db_service_get_claimed(attr))
2422                 return;
2423
2424         service = service_create(attr, client);
2425         if (!service)
2426                 return;
2427
2428         if (!create_characteristics(attr, service)) {
2429                 error("Exporting characteristics failed");
2430                 unregister_service(service);
2431                 return;
2432         }
2433
2434         queue_push_tail(client->services, service);
2435
2436 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2437         /*
2438          * Asynchronously update the "Characteristics" property of the service.
2439          * If there are any pending reads to obtain the value of the "Extended
2440          * Properties" descriptor then wait until they are complete.
2441          */
2442         if (!service->chrcs_ready && queue_isempty(service->pending_ext_props))
2443                 service->idle_id = g_idle_add(set_chrcs_ready, service);
2444 #endif
2445 }
2446
2447 static bool match_service_handle(const void *a, const void *b)
2448 {
2449         const struct service *service = a;
2450         uint16_t start_handle = PTR_TO_UINT(b);
2451
2452         return service->start_handle == start_handle;
2453 }
2454
2455 struct update_incl_data {
2456         struct service *service;
2457         bool changed;
2458 };
2459
2460 static void update_included_service(struct gatt_db_attribute *attrib,
2461                                                         void *user_data)
2462 {
2463         struct update_incl_data *update_data = user_data;
2464         struct btd_gatt_client *client = update_data->service->client;
2465         struct service *service = update_data->service;
2466         struct service *incl_service;
2467         uint16_t start_handle;
2468
2469         gatt_db_attribute_get_incl_data(attrib, NULL, &start_handle, NULL);
2470
2471         incl_service = queue_find(client->services, match_service_handle,
2472                                                 UINT_TO_PTR(start_handle));
2473
2474         if (!incl_service)
2475                 return;
2476
2477         /* Check if service is already on list */
2478         if (queue_find(service->incl_services, NULL, incl_service))
2479                 return;
2480
2481         queue_push_tail(service->incl_services, incl_service);
2482         update_data->changed = true;
2483 }
2484
2485 static void update_included_services(void *data, void *user_data)
2486 {
2487         struct btd_gatt_client *client = user_data;
2488         struct service *service = data;
2489         struct gatt_db_attribute *attr;
2490         struct update_incl_data inc_data = {
2491                 .changed = false,
2492                 .service = service,
2493         };
2494
2495         attr = gatt_db_get_attribute(client->db, service->start_handle);
2496         gatt_db_service_foreach_incl(attr, update_included_service, &inc_data);
2497
2498         if (inc_data.changed)
2499                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
2500                                                         service->path,
2501                                                         GATT_SERVICE_IFACE,
2502                                                         "Includes");
2503 }
2504
2505 static void create_services(struct btd_gatt_client *client)
2506 {
2507         DBG("Exporting objects for GATT services: %s", client->devaddr);
2508
2509         gatt_db_foreach_service(client->db, NULL, export_service, client);
2510
2511         queue_foreach(client->services, update_included_services, client);
2512 }
2513
2514 struct btd_gatt_client *btd_gatt_client_new(struct btd_device *device)
2515 {
2516         struct btd_gatt_client *client;
2517         struct gatt_db *db;
2518
2519         if (!device)
2520                 return NULL;
2521
2522         db = btd_device_get_gatt_db(device);
2523         if (!db)
2524                 return NULL;
2525
2526         client = new0(struct btd_gatt_client, 1);
2527         client->services = queue_new();
2528         client->all_notify_clients = queue_new();
2529         client->ios = queue_new();
2530         client->device = device;
2531         ba2str(device_get_address(device), client->devaddr);
2532
2533         client->db = gatt_db_ref(db);
2534
2535         return client;
2536 }
2537
2538 void btd_gatt_client_destroy(struct btd_gatt_client *client)
2539 {
2540         if (!client)
2541                 return;
2542
2543 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2544         if (client->wait_charcs_id)
2545                 g_source_remove(client->wait_charcs_id);
2546 #endif
2547         queue_destroy(client->services, unregister_service);
2548         queue_destroy(client->all_notify_clients, NULL);
2549         queue_destroy(client->ios, NULL);
2550         bt_gatt_client_unref(client->gatt);
2551         gatt_db_unref(client->db);
2552         free(client);
2553 }
2554
2555 static void register_notify(void *data, void *user_data)
2556 {
2557         struct notify_client *notify_client = data;
2558         struct btd_gatt_client *client = user_data;
2559         struct async_dbus_op *op;
2560
2561         DBG("Re-register subscribed notification client");
2562
2563         op = new0(struct async_dbus_op, 1);
2564         op->data = notify_client;
2565
2566         notify_client->notify_id = bt_gatt_client_register_notify(client->gatt,
2567                                         notify_client->chrc->value_handle,
2568                                         register_notify_cb, notify_cb,
2569                                         op, async_dbus_op_free);
2570         if (notify_client->notify_id)
2571                 return;
2572
2573         async_dbus_op_free(op);
2574
2575         DBG("Failed to re-register notification client");
2576
2577         queue_remove(notify_client->chrc->notify_clients, notify_client);
2578         queue_remove(client->all_notify_clients, notify_client);
2579
2580         notify_client_free(notify_client);
2581 }
2582
2583 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2584 static void check_chrcs_ready(void *data, void *user_data)
2585 {
2586         gboolean *chrcs_ready = user_data;
2587         struct service *service = data;
2588
2589         /*
2590         * Return FALSE if charcteristics are not ready or if there is
2591         * any pending request to read char. extended properties exist.
2592         */
2593         if (!service->chrcs_ready ||
2594                 !queue_isempty(service->pending_ext_props))
2595                 *chrcs_ready = FALSE;
2596 }
2597
2598 static gboolean check_all_chrcs_ready(gpointer user_data)
2599 {
2600         struct btd_gatt_client *client = user_data;
2601         gboolean all_chrcs_ready = TRUE;
2602         static int count = 0;
2603
2604         queue_foreach(client->services, check_chrcs_ready, &all_chrcs_ready);
2605
2606         /*
2607         * By adding below condition, forcing to call check_chrcs_ready()
2608         * function to check whether all char./extended properties are ready.
2609         * Above function would be called max. for 500 times (Assuming more
2610         * no of services). Emit signal only when all characteristics are ready.
2611         */
2612         if (all_chrcs_ready == FALSE && count < 500) {
2613                 count++;
2614                 return TRUE;
2615         }
2616
2617         /*
2618         * There are chances when all of the primary services are not found,
2619         * instead service changed is received while reading REQs in progress,
2620         * so emit signal after service changed operation is completed (if any).
2621         */
2622         if (bt_gatt_client_svc_changed_received(client->gatt))
2623                 return TRUE;
2624
2625         device_set_gatt_connected(client->device, TRUE);
2626
2627         client->wait_charcs_id = 0;
2628
2629         count = 0;
2630
2631         return FALSE;
2632 }
2633 #endif
2634
2635 void btd_gatt_client_ready(struct btd_gatt_client *client)
2636 {
2637         if (!client)
2638                 return;
2639
2640         if (!client->gatt) {
2641                 struct bt_gatt_client *gatt;
2642
2643                 gatt = btd_device_get_gatt_client(client->device);
2644                 client->gatt = bt_gatt_client_clone(gatt);
2645                 if (!client->gatt) {
2646                         error("GATT client not initialized");
2647                         return;
2648                 }
2649         }
2650
2651         client->ready = true;
2652
2653         DBG("GATT client ready");
2654
2655         create_services(client);
2656
2657         DBG("Features 0x%02x", client->features);
2658
2659         if (!client->features) {
2660                 client->features = bt_gatt_client_get_features(client->gatt);
2661                 DBG("Update Features 0x%02x", client->features);
2662                 if (client->features & BT_GATT_CHRC_CLI_FEAT_EATT)
2663                        btd_gatt_client_eatt_connect(client);
2664         }
2665
2666 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2667         /*
2668          * In case of more number of services and services having
2669          * characteristics extended properties; GattConnected signal
2670          * should be emitted only after all the characteristics are ready.
2671          * This piece of code checks all the characteristics periodically and
2672          * emit the signal if characteristics are ready.
2673          */
2674         if (client->wait_charcs_id > 0)
2675                 g_source_remove(client->wait_charcs_id);
2676
2677         client->wait_charcs_id = g_timeout_add(10,
2678                         check_all_chrcs_ready, client);
2679 #endif
2680 }
2681
2682
2683 static void eatt_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
2684 {
2685         struct btd_gatt_client *client = user_data;
2686
2687         if (gerr)
2688                 return;
2689
2690         device_attach_att(client->device, io);
2691 }
2692
2693 void btd_gatt_client_eatt_connect(struct btd_gatt_client *client)
2694 {
2695         struct bt_att *att = bt_gatt_client_get_att(client->gatt);
2696         struct btd_device *dev = client->device;
2697         struct btd_adapter *adapter = device_get_adapter(dev);
2698         GIOChannel *io;
2699         GError *gerr = NULL;
2700         char addr[18];
2701         int i;
2702
2703         if (!(client->features & BT_GATT_CHRC_CLI_FEAT_EATT))
2704                 return;
2705         if (bt_att_get_channels(att) == btd_opts.gatt_channels)
2706                 return;
2707
2708         ba2str(device_get_address(dev), addr);
2709
2710         for (i = bt_att_get_channels(att); i < btd_opts.gatt_channels; i++) {
2711                 int defer_timeout = i + 1 < btd_opts.gatt_channels ? 1 : 0;
2712
2713                 DBG("Connection attempt to: %s defer %s", addr,
2714                                         defer_timeout ? "true" : "false");
2715
2716                 /* Attempt to connect using the Ext-Flowctl */
2717                 io = bt_io_connect(eatt_connect_cb, client, NULL, &gerr,
2718                                         BT_IO_OPT_SOURCE_BDADDR,
2719                                         btd_adapter_get_address(adapter),
2720                                         BT_IO_OPT_SOURCE_TYPE,
2721                                         btd_adapter_get_address_type(adapter),
2722                                         BT_IO_OPT_DEST_BDADDR,
2723                                         device_get_address(dev),
2724                                         BT_IO_OPT_DEST_TYPE,
2725                                         device_get_le_address_type(dev),
2726                                         BT_IO_OPT_MODE, BT_IO_MODE_EXT_FLOWCTL,
2727                                         BT_IO_OPT_PSM, BT_ATT_EATT_PSM,
2728                                         BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
2729                                         BT_IO_OPT_MTU, btd_opts.gatt_mtu,
2730                                         BT_IO_OPT_DEFER_TIMEOUT, defer_timeout,
2731                                         BT_IO_OPT_INVALID);
2732                 if (!io) {
2733                         g_error_free(gerr);
2734                         gerr = NULL;
2735                         /* Fallback to legacy LE Mode */
2736                         io = bt_io_connect(eatt_connect_cb, client, NULL, &gerr,
2737                                         BT_IO_OPT_SOURCE_BDADDR,
2738                                         btd_adapter_get_address(adapter),
2739                                         BT_IO_OPT_SOURCE_TYPE,
2740                                         btd_adapter_get_address_type(adapter),
2741                                         BT_IO_OPT_DEST_BDADDR,
2742                                         device_get_address(dev),
2743                                         BT_IO_OPT_DEST_TYPE,
2744                                         device_get_le_address_type(dev),
2745                                         BT_IO_OPT_PSM, BT_ATT_EATT_PSM,
2746                                         BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
2747                                         BT_IO_OPT_MTU, btd_opts.gatt_mtu,
2748                                         BT_IO_OPT_INVALID);
2749                         if (!io) {
2750                                 error("EATT bt_io_connect(%s): %s", addr,
2751                                                         gerr->message);
2752                                 g_error_free(gerr);
2753                                 return;
2754                         }
2755                 }
2756
2757                 g_io_channel_unref(io);
2758         }
2759 }
2760
2761 void btd_gatt_client_connected(struct btd_gatt_client *client)
2762 {
2763         struct bt_gatt_client *gatt;
2764
2765         gatt = btd_device_get_gatt_client(client->device);
2766         if (!gatt) {
2767                 error("GATT client not initialized");
2768                 return;
2769         }
2770
2771         DBG("Device connected.");
2772
2773         bt_gatt_client_unref(client->gatt);
2774 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2775         /* The Client data is not getting updated
2776          * while clone logic is used, because of which
2777          * the notification callbacks and other debug callbacks
2778          * are not getting set properly, untill the clone logic
2779          * is fixed, the ref logic is used */
2780         client->gatt = bt_gatt_client_ref(gatt);
2781 #else
2782         client->gatt = bt_gatt_client_clone(gatt);
2783 #endif
2784         /*
2785          * Services have already been created before. Re-enable notifications
2786          * for any pre-registered notification sessions.
2787          */
2788         queue_foreach(client->all_notify_clients, register_notify, client);
2789 }
2790
2791 void btd_gatt_client_service_added(struct btd_gatt_client *client,
2792                                         struct gatt_db_attribute *attrib)
2793 {
2794         if (!client || !attrib || !client->ready)
2795                 return;
2796
2797         export_service(attrib, client);
2798
2799         queue_foreach(client->services, update_included_services, client);
2800 }
2801
2802 void btd_gatt_client_service_removed(struct btd_gatt_client *client,
2803                                         struct gatt_db_attribute *attrib)
2804 {
2805         uint16_t start_handle, end_handle;
2806
2807         if (!client || !attrib || !client->ready)
2808                 return;
2809
2810         gatt_db_attribute_get_service_handles(attrib, &start_handle,
2811                                                                 &end_handle);
2812
2813         DBG("GATT Services Removed - start: 0x%04x, end: 0x%04x", start_handle,
2814                                                                 end_handle);
2815         queue_remove_all(client->services, match_service_handle,
2816                                                 UINT_TO_PTR(start_handle),
2817                                                 unregister_service);
2818 }
2819
2820 static void clear_notify_id(void *data, void *user_data)
2821 {
2822         struct notify_client *client = data;
2823
2824         client->notify_id = 0;
2825 }
2826
2827 static void client_shutdown(void *data)
2828 {
2829         io_shutdown(data);
2830 }
2831
2832 void btd_gatt_client_disconnected(struct btd_gatt_client *client)
2833 {
2834         if (!client || !client->gatt)
2835                 return;
2836
2837         DBG("Device disconnected. Cleaning up.");
2838
2839 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2840         if (client->wait_charcs_id) {
2841                 g_source_remove(client->wait_charcs_id);
2842                 client->wait_charcs_id = 0;
2843         }
2844 #endif
2845         queue_remove_all(client->ios, NULL, NULL, client_shutdown);
2846
2847         /*
2848          * TODO: Once GATT over BR/EDR is properly supported, we should pass the
2849          * correct bdaddr_type based on the transport over which GATT is being
2850          * done.
2851          */
2852         queue_foreach(client->all_notify_clients, clear_notify_id, NULL);
2853
2854         bt_gatt_client_unref(client->gatt);
2855         client->gatt = NULL;
2856 }
2857
2858 struct foreach_service_data {
2859         btd_gatt_client_service_path_t func;
2860         void *user_data;
2861 };
2862
2863 static void client_service_foreach(void *data, void *user_data)
2864 {
2865         struct service *service = data;
2866         struct foreach_service_data *foreach_data = user_data;
2867
2868         foreach_data->func(service->path, foreach_data->user_data);
2869 }
2870
2871 void btd_gatt_client_foreach_service(struct btd_gatt_client *client,
2872                                         btd_gatt_client_service_path_t func,
2873                                         void *user_data)
2874 {
2875         struct foreach_service_data data;
2876
2877         if (!client)
2878                 return;
2879
2880         data.func = func;
2881         data.user_data = user_data;
2882
2883         queue_foreach(client->services, client_service_foreach, &data);
2884 }