750570c17cb633b033d5df98f239459a52a46979
[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 void write_characteristic_cb(struct gatt_db_attribute *attr, int err,
950                                                                 void *user_data)
951 {
952         struct characteristic *chrc = user_data;
953
954         if (err)
955                 return;
956
957         g_dbus_emit_property_changed_full(btd_get_dbus_connection(),
958                                 chrc->path, GATT_CHARACTERISTIC_IFACE,
959                                 "Value", G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH);
960
961 }
962
963 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
964 static void notify_characteristic_cb(struct gatt_db_attribute *attr, int err,
965                                                                 void *user_data)
966 {
967         if (err) {
968                 error("Failed to notify_characteristic_cb : %d", err);
969                 return;
970         }
971 }
972 #endif
973
974 static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
975                                         uint16_t length, void *user_data)
976 {
977         struct async_dbus_op *op = user_data;
978         struct characteristic *chrc = op->data;
979
980         if (!success)
981                 goto fail;
982
983         if (!op->offset)
984                 gatt_db_attribute_reset(chrc->attr);
985
986         if (!gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0,
987                                         NULL, write_characteristic_cb, chrc)) {
988                 error("Failed to store attribute");
989                 att_ecode = BT_ATT_ERROR_UNLIKELY;
990                 goto fail;
991         }
992
993         /* Read the stored data from db */
994         if (!gatt_db_attribute_read(chrc->attr, op->offset, 0, NULL, read_op_cb,
995                                                                         op)) {
996                 error("Failed to read database");
997                 att_ecode = BT_ATT_ERROR_UNLIKELY;
998                 goto fail;
999         }
1000
1001         chrc->read_op = NULL;
1002
1003         return;
1004
1005 fail:
1006         async_dbus_op_reply(op, att_ecode, NULL, 0);
1007         chrc->read_op = NULL;
1008 }
1009
1010 static DBusMessage *characteristic_read_value(DBusConnection *conn,
1011                                         DBusMessage *msg, void *user_data)
1012 {
1013         struct characteristic *chrc = user_data;
1014         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1015         DBusMessageIter iter;
1016         uint16_t offset = 0;
1017
1018         if (!gatt)
1019                 return btd_error_failed(msg, "Not connected");
1020
1021         dbus_message_iter_init(msg, &iter);
1022
1023         if (parse_options(&iter, &offset, NULL))
1024                 return btd_error_invalid_args(msg);
1025
1026         if (chrc->read_op) {
1027                 if (chrc->read_op->offset != offset)
1028                         return btd_error_in_progress(msg);
1029                 queue_push_tail(chrc->read_op->msgs, dbus_message_ref(msg));
1030                 return NULL;
1031         }
1032
1033         chrc->read_op = read_value(gatt, msg, chrc->value_handle, offset,
1034                                                         chrc_read_cb, chrc);
1035         if (!chrc->read_op)
1036                 return btd_error_failed(msg, "Failed to send read request");
1037
1038         return NULL;
1039 }
1040
1041 static bool chrc_write_complete(void *data)
1042 {
1043         struct characteristic *chrc = data;
1044
1045         chrc->write_op = NULL;
1046
1047         /*
1048          * The characteristic might have been unregistered during the read.
1049          * Return failure.
1050          */
1051         return !!chrc->service;
1052 }
1053
1054 static DBusMessage *characteristic_write_value(DBusConnection *conn,
1055                                         DBusMessage *msg, void *user_data)
1056 {
1057         struct characteristic *chrc = user_data;
1058         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1059         DBusMessageIter iter;
1060         uint8_t *value = NULL;
1061         int value_len = 0;
1062         bool supported = false;
1063         uint16_t offset = 0;
1064         const char *type = NULL;
1065
1066         if (!gatt)
1067                 return btd_error_failed(msg, "Not connected");
1068
1069         if (chrc->write_io)
1070                 return btd_error_not_permitted(msg, "Write acquired");
1071
1072         if (chrc->write_op)
1073                 return btd_error_in_progress(msg);
1074
1075         dbus_message_iter_init(msg, &iter);
1076
1077         if (parse_value_arg(&iter, &value, &value_len))
1078                 return btd_error_invalid_args(msg);
1079
1080         dbus_message_iter_next(&iter);
1081
1082         if (parse_options(&iter, &offset, &type))
1083                 return btd_error_invalid_args(msg);
1084
1085         /*
1086          * Decide which write to use based on characteristic properties. For now
1087          * we don't perform signed writes since gatt-client doesn't support them
1088          * and the user can always encrypt the through pairing. The procedure to
1089          * use is determined based on the following priority:
1090          *
1091          *   * "reliable-write" property set -> reliable long-write.
1092          *   * "write" property set -> write request.
1093          *     - If value is larger than MTU - 3: long-write
1094          *   * "write-without-response" property set -> write command.
1095          */
1096 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
1097         if ((!type && (chrc->ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE))
1098                         || (type && !strcasecmp(type, "reliable"))) {
1099                 supported = true;
1100                 chrc->write_op = start_long_write(msg, chrc->value_handle, gatt,
1101                                                 true, value, value_len, offset,
1102                                                 chrc, chrc_write_complete);
1103                 if (chrc->write_op)
1104                         return NULL;
1105         }
1106 #endif
1107
1108         if ((!type && chrc->props & BT_GATT_CHRC_PROP_WRITE) ||
1109                         (type && !strcasecmp(type, "request"))) {
1110                 uint16_t mtu;
1111
1112                 supported = true;
1113                 mtu = bt_gatt_client_get_mtu(gatt);
1114                 if (!mtu)
1115                         return btd_error_failed(msg, "No ATT transport");
1116
1117                 if (value_len <= mtu - 3 && !offset)
1118                         chrc->write_op = start_write_request(msg,
1119                                                 chrc->value_handle,
1120                                                 gatt, value, value_len,
1121                                                 chrc, chrc_write_complete);
1122                 else
1123                         chrc->write_op = start_long_write(msg,
1124                                                 chrc->value_handle, gatt,
1125                                                 false, value, value_len, offset,
1126                                                 chrc, chrc_write_complete);
1127
1128                 if (chrc->write_op)
1129                         return NULL;
1130         }
1131
1132         if ((type && strcasecmp(type, "command")) || offset || (!type &&
1133                         !(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP)))
1134                 goto fail;
1135
1136         supported = true;
1137
1138         if (bt_gatt_client_write_without_response(gatt,
1139                                         chrc->value_handle,
1140                                         chrc->props & BT_GATT_CHRC_PROP_AUTH,
1141                                         value, value_len))
1142                 return dbus_message_new_method_return(msg);
1143
1144 fail:
1145         if (supported)
1146                 return btd_error_failed(msg, "Failed to initiate write");
1147
1148         return btd_error_not_supported(msg);
1149 }
1150
1151 static bool sock_read(struct io *io, void *user_data)
1152 {
1153         struct characteristic *chrc = user_data;
1154         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1155         struct msghdr msg;
1156         uint8_t buf[512];
1157         struct iovec iov;
1158         int fd = io_get_fd(io);
1159         ssize_t bytes_read;
1160
1161         iov.iov_base = buf;
1162         iov.iov_len = sizeof(buf);
1163
1164         memset(&msg, 0, sizeof(msg));
1165         msg.msg_iov = &iov;
1166         msg.msg_iovlen = 1;
1167
1168         bytes_read = recvmsg(fd, &msg, MSG_DONTWAIT);
1169         if (bytes_read < 0) {
1170                 error("recvmsg: %s", strerror(errno));
1171                 return false;
1172         }
1173
1174         if (!gatt || bytes_read == 0)
1175                 return false;
1176
1177         bt_gatt_client_write_without_response(gatt, chrc->value_handle,
1178                                         chrc->props & BT_GATT_CHRC_PROP_AUTH,
1179                                         buf, bytes_read);
1180
1181         return true;
1182 }
1183
1184 static void sock_io_destroy(struct sock_io *io)
1185 {
1186         if (io->destroy)
1187                 io->destroy(io->data);
1188
1189         if (io->msg)
1190                 dbus_message_unref(io->msg);
1191
1192         io_destroy(io->io);
1193         free(io);
1194 }
1195
1196 static void destroy_sock(struct characteristic *chrc,
1197                                                         struct io *io)
1198 {
1199         queue_remove(chrc->service->client->ios, io);
1200
1201         if (chrc->write_io && io == chrc->write_io->io) {
1202                 sock_io_destroy(chrc->write_io);
1203                 chrc->write_io = NULL;
1204                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1205                                                 chrc->path,
1206                                                 GATT_CHARACTERISTIC_IFACE,
1207                                                 "WriteAcquired");
1208         } else if (chrc->notify_io) {
1209                 sock_io_destroy(chrc->notify_io);
1210                 chrc->notify_io = NULL;
1211                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1212                                                 chrc->path,
1213                                                 GATT_CHARACTERISTIC_IFACE,
1214                                                 "NotifyAcquired");
1215         }
1216 }
1217
1218 static bool sock_hup(struct io *io, void *user_data)
1219 {
1220         struct characteristic *chrc = user_data;
1221
1222         DBG("%s: io %p", chrc->path, io);
1223
1224         destroy_sock(chrc, io);
1225
1226         return false;
1227 }
1228
1229 static DBusMessage *create_sock(struct characteristic *chrc,
1230                                                 DBusMessage *msg)
1231 {
1232         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1233         int fds[2];
1234         struct io *io;
1235         bool dir;
1236         uint16_t mtu;
1237         DBusMessage *reply;
1238
1239         if (!gatt || !bt_gatt_client_is_ready(gatt))
1240                 return btd_error_failed(msg, "Not connected");
1241
1242         if (socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC,
1243                                                                 0, fds) < 0)
1244                 return btd_error_failed(msg, strerror(errno));
1245
1246         dir = dbus_message_has_member(msg, "AcquireWrite");
1247
1248         io = io_new(fds[!dir]);
1249         if (!io) {
1250                 close(fds[0]);
1251                 close(fds[1]);
1252                 return btd_error_failed(msg, strerror(EIO));
1253         }
1254
1255         io_set_close_on_destroy(io, true);
1256
1257         if (!io_set_read_handler(io, sock_read, chrc, NULL))
1258                 goto fail;
1259
1260         if (!io_set_disconnect_handler(io, sock_hup, chrc, NULL))
1261                 goto fail;
1262
1263         mtu = bt_gatt_client_get_mtu(gatt);
1264
1265         reply = g_dbus_create_reply(msg, DBUS_TYPE_UNIX_FD, &fds[dir],
1266                                         DBUS_TYPE_UINT16, &mtu,
1267                                         DBUS_TYPE_INVALID);
1268
1269         close(fds[dir]);
1270
1271         if (dir) {
1272                 chrc->write_io->io = io;
1273                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1274                                                 chrc->path,
1275                                                 GATT_CHARACTERISTIC_IFACE,
1276                                                 "WriteAcquired");
1277         } else {
1278                 chrc->notify_io->io = io;
1279                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1280                                                 chrc->path,
1281                                                 GATT_CHARACTERISTIC_IFACE,
1282                                                 "NotifyAcquired");
1283         }
1284
1285         queue_push_tail(chrc->service->client->ios, io);
1286
1287         DBG("%s: sender %s io %p", dbus_message_get_member(msg),
1288                                         dbus_message_get_sender(msg), io);
1289
1290         return reply;
1291
1292 fail:
1293         io_destroy(io);
1294         close(fds[dir]);
1295         return btd_error_failed(msg, strerror(EIO));
1296 }
1297
1298 static void characteristic_ready(bool success, uint8_t ecode, void *user_data)
1299 {
1300         struct characteristic *chrc = user_data;
1301         DBusMessage *reply;
1302
1303         chrc->ready_id = 0;
1304
1305         if (chrc->write_io && chrc->write_io->msg) {
1306                 reply = create_sock(chrc, chrc->write_io->msg);
1307
1308                 g_dbus_send_message(btd_get_dbus_connection(), reply);
1309
1310                 dbus_message_unref(chrc->write_io->msg);
1311                 chrc->write_io->msg = NULL;
1312         }
1313
1314         if (chrc->notify_io && chrc->notify_io->msg) {
1315                 reply = create_sock(chrc, chrc->notify_io->msg);
1316
1317                 g_dbus_send_message(btd_get_dbus_connection(), reply);
1318
1319                 dbus_message_unref(chrc->notify_io->msg);
1320                 chrc->notify_io->msg = NULL;
1321         }
1322 }
1323
1324 static DBusMessage *characteristic_acquire_write(DBusConnection *conn,
1325                                         DBusMessage *msg, void *user_data)
1326 {
1327         struct characteristic *chrc = user_data;
1328         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1329
1330         if (!gatt)
1331                 return btd_error_failed(msg, "Not connected");
1332
1333         if (chrc->write_io)
1334                 return btd_error_not_permitted(msg, "Write acquired");
1335
1336         if (!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP))
1337                 return btd_error_not_supported(msg);
1338
1339         chrc->write_io = new0(struct sock_io, 1);
1340
1341         if (!bt_gatt_client_is_ready(gatt)) {
1342                 /* GATT not ready, wait until it becomes ready */
1343                 if (!chrc->ready_id)
1344                         chrc->ready_id = bt_gatt_client_ready_register(gatt,
1345                                                         characteristic_ready,
1346                                                         chrc, NULL);
1347                 chrc->write_io->msg = dbus_message_ref(msg);
1348                 return NULL;
1349         }
1350
1351         return create_sock(chrc, msg);
1352 }
1353
1354 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1355 static DBusMessage *characteristic_write_value_by_type(DBusConnection *conn,
1356                                         DBusMessage *msg, void *user_data)
1357 {
1358         struct characteristic *chrc = user_data;
1359         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1360         DBusMessageIter iter;
1361         uint8_t *value = NULL;
1362         int value_len = 0;
1363         bool supported = false;
1364         uint8_t write_type = 0;
1365         uint16_t offset = 0;
1366
1367         if (!gatt)
1368                 return btd_error_failed(msg, "Not connected");
1369
1370         if (chrc->write_op)
1371                 return btd_error_in_progress(msg);
1372
1373         dbus_message_iter_init(msg, &iter);
1374
1375         if (parse_type_value_arg(&iter, &write_type, &value, &value_len))
1376                 return btd_error_invalid_args(msg);
1377
1378         if (parse_options(&iter, &offset,NULL))
1379                 return btd_error_invalid_args(msg);
1380
1381         if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_WRITE) {
1382                 uint16_t mtu;
1383
1384                 supported = true;
1385                 mtu = bt_gatt_client_get_mtu(gatt);
1386                 if (!mtu)
1387                         return btd_error_failed(msg, "No ATT transport");
1388
1389                 if (value_len <= mtu - 3 && !offset)
1390                         chrc->write_op = start_write_request(msg,
1391                                                 chrc->value_handle,
1392                                                 gatt, value, value_len,
1393                                                 chrc, chrc_write_complete);
1394                 else
1395                         chrc->write_op = start_long_write(msg,
1396                                                 chrc->value_handle, gatt,
1397                                                 false, value, value_len, offset,
1398                                                 chrc, chrc_write_complete);
1399
1400                 if (chrc->write_op)
1401                         return NULL;
1402         } else if ((write_type & chrc->props) ==
1403                         BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) {
1404                 supported = true;
1405                 chrc->write_op = start_write_cmd(msg, chrc->value_handle, gatt,
1406                                                  false, value, value_len,
1407                                                  chrc, chrc_write_complete);
1408                 if (chrc->write_op)
1409                         return NULL;
1410         } else if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_AUTH) {
1411                 supported = true;
1412                 chrc->write_op = start_write_cmd(msg, chrc->value_handle, gatt,
1413                                                  true, value, value_len,
1414                                                  chrc, chrc_write_complete);
1415                 if (chrc->write_op)
1416                         return NULL;
1417         }
1418
1419         if (supported)
1420                 return btd_error_failed(msg, "Failed to initiate write");
1421
1422         return btd_error_not_supported(msg);
1423 }
1424 #endif
1425
1426 struct notify_client {
1427         struct characteristic *chrc;
1428         int ref_count;
1429         char *owner;
1430         guint watch;
1431         unsigned int notify_id;
1432 };
1433
1434 static void notify_client_free(struct notify_client *client)
1435 {
1436         DBG("owner %s", client->owner);
1437
1438         g_dbus_remove_watch(btd_get_dbus_connection(), client->watch);
1439         bt_gatt_client_unregister_notify(client->chrc->service->client->gatt,
1440                                                         client->notify_id);
1441         free(client->owner);
1442         free(client);
1443 }
1444
1445 static void notify_client_unref(void *data)
1446 {
1447         struct notify_client *client = data;
1448
1449         DBG("owner %s", client->owner);
1450
1451         if (__sync_sub_and_fetch(&client->ref_count, 1))
1452                 return;
1453
1454         notify_client_free(client);
1455 }
1456
1457 static struct notify_client *notify_client_ref(struct notify_client *client)
1458 {
1459         DBG("owner %s", client->owner);
1460
1461         __sync_fetch_and_add(&client->ref_count, 1);
1462
1463         return client;
1464 }
1465
1466 static bool match_notifying(const void *a, const void *b)
1467 {
1468         const struct notify_client *client = a;
1469
1470         return !!client->notify_id;
1471 }
1472
1473 static void update_notifying(struct characteristic *chrc)
1474 {
1475         if (!chrc->notifying)
1476                 return;
1477
1478         if (queue_find(chrc->notify_clients, match_notifying, NULL))
1479                 return;
1480
1481         chrc->notifying = false;
1482
1483         g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
1484                                                 GATT_CHARACTERISTIC_IFACE,
1485                                                 "Notifying");
1486 }
1487
1488 static void notify_client_disconnect(DBusConnection *conn, void *user_data)
1489 {
1490         struct notify_client *client = user_data;
1491         struct characteristic *chrc = client->chrc;
1492
1493         DBG("owner %s", client->owner);
1494
1495         queue_remove(chrc->notify_clients, client);
1496         queue_remove(chrc->service->client->all_notify_clients, client);
1497
1498         update_notifying(chrc);
1499
1500         notify_client_unref(client);
1501 }
1502
1503 static struct notify_client *notify_client_create(struct characteristic *chrc,
1504                                                         const char *owner)
1505 {
1506         struct notify_client *client;
1507
1508         client = new0(struct notify_client, 1);
1509         client->chrc = chrc;
1510         client->owner = strdup(owner);
1511         if (!client->owner) {
1512                 free(client);
1513                 return NULL;
1514         }
1515
1516         client->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
1517                                                 owner, notify_client_disconnect,
1518                                                 client, NULL);
1519         if (!client->watch) {
1520                 free(client->owner);
1521                 free(client);
1522                 return NULL;
1523         }
1524
1525         return notify_client_ref(client);
1526 }
1527
1528 static bool match_notify_sender(const void *a, const void *b)
1529 {
1530         const struct notify_client *client = a;
1531         const char *sender = b;
1532
1533         return strcmp(client->owner, sender) == 0;
1534 }
1535
1536 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1537 void gatt_characteristic_value_changed(struct notify_client *client, const uint8_t *data, uint16_t data_len, void *user_data)
1538 {
1539         struct characteristic *chrc = user_data;
1540         char *chrc_path = strdup(chrc->path);
1541         dbus_int32_t result = 0;
1542
1543         g_dbus_emit_signal_to_dest(btd_get_dbus_connection(),
1544                 client->owner, chrc_path,
1545                 GATT_CHARACTERISTIC_IFACE, "GattValueChanged",
1546                 DBUS_TYPE_INT32, &result,
1547                 DBUS_TYPE_STRING, &chrc_path,
1548                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, data_len,
1549                 DBUS_TYPE_INVALID);
1550
1551         if (chrc_path)
1552                 free(chrc_path);
1553
1554 }
1555 #endif
1556
1557 static void notify_cb(uint16_t value_handle, const uint8_t *value,
1558                                         uint16_t length, void *user_data)
1559 {
1560         struct async_dbus_op *op = user_data;
1561         struct notify_client *client = op->data;
1562         struct characteristic *chrc = client->chrc;
1563
1564         /*
1565          * Even if the value didn't change, we want to send a PropertiesChanged
1566          * signal so that we propagate the notification/indication to
1567          * applications.
1568          */
1569         gatt_db_attribute_reset(chrc->attr);
1570 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1571         gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
1572                                                 notify_characteristic_cb, chrc);
1573
1574         gatt_characteristic_value_changed(client, value, length, chrc);
1575 #else
1576         gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
1577                                                 write_characteristic_cb, chrc);
1578 #endif
1579 }
1580
1581 static void create_notify_reply(struct async_dbus_op *op, bool success,
1582                                                         uint8_t att_ecode)
1583 {
1584         int err;
1585
1586         if (success)
1587                 err = 0;
1588         else
1589                 err = att_ecode ? att_ecode : -ENOENT;
1590
1591         async_dbus_op_reply(op, err, NULL, -1);
1592 }
1593
1594 static void register_notify_cb(uint16_t att_ecode, void *user_data)
1595 {
1596         struct async_dbus_op *op = user_data;
1597         struct notify_client *client = op->data;
1598         struct characteristic *chrc = client->chrc;
1599
1600         if (att_ecode) {
1601                 queue_remove(chrc->notify_clients, client);
1602                 queue_remove(chrc->service->client->all_notify_clients, client);
1603                 notify_client_free(client);
1604
1605                 create_notify_reply(op, false, att_ecode);
1606
1607                 return;
1608         }
1609
1610         if (!chrc->notifying) {
1611                 chrc->notifying = true;
1612                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1613                                         chrc->path, GATT_CHARACTERISTIC_IFACE,
1614                                         "Notifying");
1615         }
1616
1617         create_notify_reply(op, true, 0);
1618 }
1619
1620 static void notify_io_cb(uint16_t value_handle, const uint8_t *value,
1621                                         uint16_t length, void *user_data)
1622 {
1623         struct msghdr msg;
1624         struct iovec iov;
1625         struct notify_client *client = user_data;
1626         struct characteristic *chrc = client->chrc;
1627         int err;
1628
1629         /* Drop notification if the pipe is not ready */
1630         if (!chrc->notify_io ||  !chrc->notify_io->io)
1631                 return;
1632
1633         iov.iov_base = (void *) value;
1634         iov.iov_len = length;
1635
1636         memset(&msg, 0, sizeof(msg));
1637         msg.msg_iov = &iov;
1638         msg.msg_iovlen = 1;
1639
1640         err = sendmsg(io_get_fd(chrc->notify_io->io), &msg, MSG_NOSIGNAL);
1641         if (err < 0)
1642                 error("sendmsg: %s", strerror(errno));
1643 }
1644
1645 static void register_notify_io_cb(uint16_t att_ecode, void *user_data)
1646 {
1647         struct notify_client *client = user_data;
1648         struct characteristic *chrc = client->chrc;
1649         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1650
1651         if (att_ecode) {
1652                 queue_remove(chrc->notify_clients, client);
1653                 notify_client_free(client);
1654                 return;
1655         }
1656
1657         if (!bt_gatt_client_is_ready(gatt)) {
1658                 if (!chrc->ready_id)
1659                         chrc->ready_id = bt_gatt_client_ready_register(gatt,
1660                                                         characteristic_ready,
1661                                                         chrc, NULL);
1662                 return;
1663         }
1664
1665         characteristic_ready(true, 0, chrc);
1666 }
1667
1668 static void notify_io_destroy(void *data)
1669 {
1670         struct notify_client *client = data;
1671
1672         if (queue_remove(client->chrc->notify_clients, client))
1673                 notify_client_unref(client);
1674 }
1675
1676 static DBusMessage *characteristic_acquire_notify(DBusConnection *conn,
1677                                         DBusMessage *msg, void *user_data)
1678 {
1679         struct characteristic *chrc = user_data;
1680         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1681         const char *sender = dbus_message_get_sender(msg);
1682         struct notify_client *client;
1683
1684         if (!gatt)
1685                 return btd_error_failed(msg, "Not connected");
1686
1687         if (chrc->notify_io)
1688                 return btd_error_not_permitted(msg, "Notify acquired");
1689
1690         /* Each client can only have one active notify session. */
1691         if (!queue_isempty(chrc->notify_clients))
1692                 return btd_error_in_progress(msg);
1693
1694         if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY))
1695                 return btd_error_not_supported(msg);
1696
1697         client = notify_client_create(chrc, sender);
1698         if (!client)
1699                 return btd_error_failed(msg, "Failed allocate notify session");
1700
1701 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1702         chrc->notify_io = new0(struct sock_io, 1);
1703         chrc->notify_io->data = client;
1704         chrc->notify_io->msg = dbus_message_ref(msg);
1705         chrc->notify_io->destroy = notify_io_destroy;
1706 #endif
1707         client->notify_id = bt_gatt_client_register_notify(gatt,
1708                                                 chrc->value_handle,
1709                                                 register_notify_io_cb,
1710                                                 notify_io_cb,
1711                                                 client, NULL);
1712         if (!client->notify_id) {
1713                 notify_client_unref(client);
1714 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1715                 dbus_message_unref(chrc->notify_io->msg);
1716                 g_free(chrc->notify_io);
1717                 chrc->notify_io = NULL;
1718 #endif
1719                 return btd_error_failed(msg, "Failed to subscribe");
1720         }
1721
1722         queue_push_tail(chrc->notify_clients, client);
1723
1724 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
1725         chrc->notify_io = new0(struct sock_io, 1);
1726         chrc->notify_io->data = client;
1727         chrc->notify_io->msg = dbus_message_ref(msg);
1728         chrc->notify_io->destroy = notify_io_destroy;
1729 #endif
1730
1731         return NULL;
1732 }
1733
1734 static DBusMessage *characteristic_start_notify(DBusConnection *conn,
1735                                         DBusMessage *msg, void *user_data)
1736 {
1737         struct characteristic *chrc = user_data;
1738         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1739         const char *sender = dbus_message_get_sender(msg);
1740         struct async_dbus_op *op;
1741         struct notify_client *client;
1742         struct btd_device *device = chrc->service->client->device;
1743
1744         if (device_is_disconnecting(device)) {
1745                 error("Device is disconnecting. StartNotify is not allowed.");
1746                 return btd_error_not_connected(msg);
1747         }
1748
1749         if (chrc->notify_io)
1750                 return btd_error_not_permitted(msg, "Notify acquired");
1751
1752         if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
1753                                 chrc->props & BT_GATT_CHRC_PROP_INDICATE))
1754                 return btd_error_not_supported(msg);
1755
1756         /* Each client can only have one active notify session. */
1757         client = queue_find(chrc->notify_clients, match_notify_sender, sender);
1758         if (client)
1759                 return client->notify_id ?
1760                                 g_dbus_create_reply(msg, DBUS_TYPE_INVALID) :
1761                                 btd_error_in_progress(msg);
1762
1763         client = notify_client_create(chrc, sender);
1764         if (!client)
1765                 return btd_error_failed(msg, "Failed allocate notify session");
1766
1767         queue_push_tail(chrc->notify_clients, client);
1768         queue_push_tail(chrc->service->client->all_notify_clients, client);
1769
1770         /*
1771          * If the device is currently not connected, return success. We will
1772          * automatically try and register all clients when a GATT client becomes
1773          * ready.
1774          */
1775         if (!gatt) {
1776                 DBusMessage *reply;
1777
1778                 reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1779                 if (reply)
1780                         return reply;
1781
1782                 /*
1783                  * Clean up and respond with an error instead of timing out to
1784                  * avoid any ambiguities.
1785                  */
1786                 error("Failed to construct D-Bus message reply");
1787                 goto fail;
1788         }
1789
1790         op = async_dbus_op_new(msg, client);
1791
1792         client->notify_id = bt_gatt_client_register_notify(gatt,
1793                                                 chrc->value_handle,
1794                                                 register_notify_cb, notify_cb,
1795                                                 op, async_dbus_op_free);
1796         if (client->notify_id)
1797                 return NULL;
1798
1799         async_dbus_op_free(op);
1800
1801 fail:
1802         queue_remove(chrc->notify_clients, client);
1803         queue_remove(chrc->service->client->all_notify_clients, client);
1804
1805         /* Directly free the client */
1806         notify_client_free(client);
1807
1808         return btd_error_failed(msg, "Failed to register notify session");
1809 }
1810
1811 static DBusMessage *characteristic_stop_notify(DBusConnection *conn,
1812                                         DBusMessage *msg, void *user_data)
1813 {
1814         struct characteristic *chrc = user_data;
1815         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1816         const char *sender = dbus_message_get_sender(msg);
1817         struct notify_client *client;
1818
1819         if (chrc->notify_io) {
1820                 destroy_sock(chrc, chrc->notify_io->io);
1821                 return dbus_message_new_method_return(msg);
1822         }
1823
1824
1825         client = queue_remove_if(chrc->notify_clients, match_notify_sender,
1826                                                         (void *) sender);
1827         if (!client)
1828                 return btd_error_failed(msg, "No notify session started");
1829
1830         queue_remove(chrc->service->client->all_notify_clients, client);
1831         bt_gatt_client_unregister_notify(gatt, client->notify_id);
1832         update_notifying(chrc);
1833
1834         notify_client_unref(client);
1835
1836         return dbus_message_new_method_return(msg);
1837 }
1838
1839 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1840 static void append_desc_path(void *data, void *user_data)
1841 {
1842         struct descriptor *desc = data;
1843         DBusMessageIter *array = user_data;
1844
1845         dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH,
1846                                                                 &desc->path);
1847 }
1848
1849 static gboolean characteristic_get_descriptors(
1850                                         const GDBusPropertyTable *property,
1851                                         DBusMessageIter *iter, void *data)
1852 {
1853         struct characteristic *chrc = data;
1854         DBusMessageIter array;
1855
1856         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "o", &array);
1857
1858         queue_foreach(chrc->descs, append_desc_path, &array);
1859
1860         dbus_message_iter_close_container(iter, &array);
1861
1862         return TRUE;
1863 }
1864 #endif
1865
1866 static const GDBusPropertyTable characteristic_properties[] = {
1867         { "UUID", "s", characteristic_get_uuid, NULL, NULL },
1868         { "Service", "o", characteristic_get_service, NULL, NULL },
1869         { "Value", "ay", characteristic_get_value, NULL,
1870                                         characteristic_value_exists },
1871 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1872         { "ChangedValue", "ay", characteristic_get_value, NULL,
1873                                         characteristic_value_exists },
1874 #endif
1875         { "Notifying", "b", characteristic_get_notifying, NULL,
1876                                         characteristic_notifying_exists },
1877         { "Flags", "as", characteristic_get_flags, NULL, NULL },
1878         { "WriteAcquired", "b", characteristic_get_write_acquired, NULL,
1879                                 characteristic_write_acquired_exists },
1880         { "NotifyAcquired", "b", characteristic_get_notify_acquired, NULL,
1881                                 characteristic_notify_acquired_exists },
1882         { "MTU", "q", characteristic_get_mtu, NULL, NULL },
1883 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1884         { "Descriptors", "ao", characteristic_get_descriptors },
1885 #endif
1886         { }
1887 };
1888
1889 static const GDBusMethodTable characteristic_methods[] = {
1890         { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
1891                                         GDBUS_ARGS({ "value", "ay" }),
1892                                         characteristic_read_value) },
1893         { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
1894                                                 { "options", "a{sv}" }),
1895                                         NULL,
1896                                         characteristic_write_value) },
1897         { GDBUS_ASYNC_METHOD("AcquireWrite",
1898                                         GDBUS_ARGS({ "options", "a{sv}" }),
1899                                         GDBUS_ARGS({ "fd", "h" },
1900                                                 { "mtu", "q" }),
1901                                         characteristic_acquire_write) },
1902         { GDBUS_ASYNC_METHOD("AcquireNotify",
1903                                         GDBUS_ARGS({ "options", "a{sv}" }),
1904                                         GDBUS_ARGS({ "fd", "h" },
1905                                                 { "mtu", "q" }),
1906                                         characteristic_acquire_notify) },
1907 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1908         { GDBUS_ASYNC_METHOD("WriteValuebyType",
1909                                         GDBUS_ARGS({ "type", "y" }, { "value", "ay" },
1910                                                 { "options", "a{sv}" }),
1911                                         NULL,
1912                                         characteristic_write_value_by_type) },
1913 #endif
1914         { GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL,
1915                                         characteristic_start_notify) },
1916         { GDBUS_METHOD("StopNotify", NULL, NULL,
1917                                         characteristic_stop_notify) },
1918         { }
1919 };
1920
1921 static void remove_client(void *data)
1922 {
1923         struct notify_client *ntfy_client = data;
1924         struct btd_gatt_client *client = ntfy_client->chrc->service->client;
1925
1926         queue_remove(client->all_notify_clients, ntfy_client);
1927
1928         notify_client_unref(ntfy_client);
1929 }
1930
1931 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
1932 static const GDBusSignalTable service_signals[] = {
1933         { GDBUS_SIGNAL("GattServiceAdded",
1934                         GDBUS_ARGS({ "Service Path","s"})) },
1935         { }
1936 };
1937 static const GDBusSignalTable characteristic_signals[] = {
1938         { GDBUS_SIGNAL("GattValueChanged",
1939                         GDBUS_ARGS({ "Result", "i"},
1940                                         { "Characteristic Path","s"},
1941                                         { "GattData", "ay"})) },
1942         { }
1943 };
1944 #endif
1945
1946 static void characteristic_free(void *data)
1947 {
1948         struct characteristic *chrc = data;
1949         struct bt_gatt_client *gatt = chrc->service->client->gatt;
1950         struct bt_att *att;
1951
1952         /* List should be empty here */
1953         queue_destroy(chrc->descs, NULL);
1954
1955         if (chrc->write_io) {
1956                 queue_remove(chrc->service->client->ios, chrc->write_io->io);
1957                 sock_io_destroy(chrc->write_io);
1958         }
1959
1960         if (chrc->notify_io) {
1961                 queue_remove(chrc->service->client->ios, chrc->notify_io->io);
1962                 sock_io_destroy(chrc->notify_io);
1963         }
1964
1965         queue_destroy(chrc->notify_clients, remove_client);
1966
1967         att = bt_gatt_client_get_att(gatt);
1968         if (att)
1969                 bt_att_unregister_exchange(att, chrc->exchange_id);
1970
1971         g_free(chrc->path);
1972         free(chrc);
1973 }
1974
1975 static void att_exchange(uint16_t mtu, void *user_data)
1976 {
1977         struct characteristic *chrc = user_data;
1978
1979         g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
1980                                         GATT_CHARACTERISTIC_IFACE, "MTU");
1981 }
1982
1983 static struct characteristic *characteristic_create(
1984                                                 struct gatt_db_attribute *attr,
1985                                                 struct service *service)
1986 {
1987         struct characteristic *chrc;
1988         struct bt_gatt_client *gatt = service->client->gatt;
1989         struct bt_att *att;
1990         bt_uuid_t uuid;
1991
1992         chrc = new0(struct characteristic, 1);
1993         chrc->descs = queue_new();
1994         chrc->notify_clients = queue_new();
1995         chrc->service = service;
1996
1997 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
1998         gatt_db_attribute_get_char_data(attr, &chrc->handle,
1999                                                         &chrc->value_handle,
2000                                                         &chrc->props,
2001                                                         &chrc->ext_props,
2002                                                         &uuid);
2003 #else
2004         if (!gatt_db_attribute_get_char_data(attr, &chrc->handle,
2005                                                         &chrc->value_handle,
2006                                                         &chrc->props,
2007                                                         &chrc->ext_props,
2008                                                         &uuid)) {
2009                 queue_destroy(chrc->descs, NULL);
2010                 queue_destroy(chrc->notify_clients, NULL);
2011                 free(chrc);
2012                 return NULL;
2013         }
2014 #endif
2015
2016         chrc->attr = gatt_db_get_attribute(service->client->db,
2017                                                         chrc->value_handle);
2018         if (!chrc->attr) {
2019                 error("Attribute 0x%04x not found", chrc->value_handle);
2020                 characteristic_free(chrc);
2021                 return NULL;
2022         }
2023
2024         bt_uuid_to_uuid128(&uuid, &chrc->uuid);
2025
2026         chrc->path = g_strdup_printf("%s/char%04x", service->path,
2027                                                                 chrc->handle);
2028
2029         if (!g_dbus_register_interface(btd_get_dbus_connection(), chrc->path,
2030                                                 GATT_CHARACTERISTIC_IFACE,
2031 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2032                                                 characteristic_methods, characteristic_signals,
2033 #else
2034                                                 characteristic_methods, NULL,
2035 #endif
2036                                                 characteristic_properties,
2037                                                 chrc, characteristic_free)) {
2038                 error("Unable to register GATT characteristic with handle "
2039                                                         "0x%04x", chrc->handle);
2040                 characteristic_free(chrc);
2041
2042                 return NULL;
2043         }
2044
2045         att = bt_gatt_client_get_att(gatt);
2046         if (att)
2047                 chrc->exchange_id = bt_att_register_exchange(att, att_exchange,
2048                                                                 chrc, NULL);
2049
2050         DBG("Exported GATT characteristic: %s", chrc->path);
2051
2052         return chrc;
2053 }
2054
2055 static void unregister_characteristic(void *data)
2056 {
2057         struct characteristic *chrc = data;
2058         struct bt_gatt_client *gatt = chrc->service->client->gatt;
2059
2060         DBG("Removing GATT characteristic: %s", chrc->path);
2061
2062         if (chrc->read_op)
2063                 bt_gatt_client_cancel(gatt, chrc->read_op->id);
2064
2065         if (chrc->write_op)
2066                 bt_gatt_client_cancel(gatt, chrc->write_op->id);
2067
2068         queue_remove_all(chrc->descs, NULL, NULL, unregister_descriptor);
2069
2070         g_dbus_unregister_interface(btd_get_dbus_connection(), chrc->path,
2071                                                 GATT_CHARACTERISTIC_IFACE);
2072 }
2073
2074 static gboolean service_get_uuid(const GDBusPropertyTable *property,
2075                                         DBusMessageIter *iter, void *data)
2076 {
2077         char uuid[MAX_LEN_UUID_STR + 1];
2078         const char *ptr = uuid;
2079         struct service *service = data;
2080
2081         bt_uuid_to_string(&service->uuid, uuid, sizeof(uuid));
2082         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
2083
2084         return TRUE;
2085 }
2086
2087 static gboolean service_get_device(const GDBusPropertyTable *property,
2088                                         DBusMessageIter *iter, void *data)
2089 {
2090         struct service *service = data;
2091         const char *str = device_get_path(service->client->device);
2092
2093         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &str);
2094
2095         return TRUE;
2096 }
2097
2098 static gboolean service_get_primary(const GDBusPropertyTable *property,
2099                                         DBusMessageIter *iter, void *data)
2100 {
2101         struct service *service = data;
2102         dbus_bool_t primary;
2103
2104         primary = service->primary ? TRUE : FALSE;
2105
2106         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &primary);
2107
2108         return TRUE;
2109 }
2110
2111 static void append_incl_service_path(void *data, void *user_data)
2112 {
2113         struct service *incl_service = data;
2114         DBusMessageIter *array = user_data;
2115
2116         dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH,
2117                                         &incl_service->path);
2118 }
2119
2120 static gboolean service_get_includes(const GDBusPropertyTable *property,
2121                                         DBusMessageIter *iter, void *data)
2122 {
2123         struct service *service = data;
2124         DBusMessageIter array;
2125
2126         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{o}", &array);
2127
2128         queue_foreach(service->incl_services, append_incl_service_path, &array);
2129
2130         dbus_message_iter_close_container(iter, &array);
2131
2132         return TRUE;
2133
2134 }
2135
2136 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2137 static void append_chrc_path(void *data, void *user_data)
2138 {
2139         struct characteristic *chrc = data;
2140         DBusMessageIter *array = user_data;
2141
2142         dbus_message_iter_append_basic(array, DBUS_TYPE_OBJECT_PATH,
2143                                                                 &chrc->path);
2144 }
2145
2146 static gboolean service_get_characteristics(const GDBusPropertyTable *property,
2147                                         DBusMessageIter *iter, void *data)
2148 {
2149         struct service *service = data;
2150         DBusMessageIter array;
2151
2152         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "o", &array);
2153
2154         if (service->chrcs_ready)
2155                 queue_foreach(service->chrcs, append_chrc_path, &array);
2156
2157         dbus_message_iter_close_container(iter, &array);
2158
2159         return TRUE;
2160 }
2161 #endif
2162
2163 static const GDBusPropertyTable service_properties[] = {
2164         { "UUID", "s", service_get_uuid },
2165         { "Device", "o", service_get_device },
2166         { "Primary", "b", service_get_primary },
2167         { "Includes", "ao", service_get_includes },
2168 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2169         { "Characteristics", "ao", service_get_characteristics },
2170 #endif
2171         { }
2172 };
2173
2174 static void service_free(void *data)
2175 {
2176         struct service *service = data;
2177
2178         queue_destroy(service->chrcs, NULL);  /* List should be empty here */
2179         queue_destroy(service->incl_services, NULL);
2180         g_free(service->path);
2181         free(service);
2182 }
2183
2184 static struct service *service_create(struct gatt_db_attribute *attr,
2185                                                 struct btd_gatt_client *client)
2186 {
2187         struct service *service;
2188         const char *device_path = device_get_path(client->device);
2189         bt_uuid_t uuid;
2190
2191         service = new0(struct service, 1);
2192         service->chrcs = queue_new();
2193         service->incl_services = queue_new();
2194         service->client = client;
2195
2196         gatt_db_attribute_get_service_data(attr, &service->start_handle,
2197                                                         &service->end_handle,
2198                                                         &service->primary,
2199                                                         &uuid);
2200         bt_uuid_to_uuid128(&uuid, &service->uuid);
2201
2202         service->path = g_strdup_printf("%s/service%04x", device_path,
2203                                                         service->start_handle);
2204
2205         if (!g_dbus_register_interface(btd_get_dbus_connection(), service->path,
2206                                                 GATT_SERVICE_IFACE,
2207 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2208                                                 NULL, service_signals,
2209 #else
2210                                                 NULL, NULL,
2211 #endif
2212                                                 service_properties,
2213                                                 service, service_free)) {
2214                 error("Unable to register GATT service with handle 0x%04x for "
2215                                                         "device %s",
2216                                                         service->start_handle,
2217                                                         client->devaddr);
2218                 service_free(service);
2219
2220                 return NULL;
2221         }
2222
2223         DBG("Exported GATT service: %s", service->path);
2224
2225         /* Set service active so we can skip discovering next time */
2226         gatt_db_service_set_active(attr, true);
2227
2228         /* Mark the service as claimed since it going to be exported */
2229         gatt_db_service_set_claimed(attr, true);
2230
2231         return service;
2232 }
2233
2234 static void on_service_removed(void *data, void *user_data)
2235 {
2236         struct service *service = data;
2237         struct service *removed_service = user_data;
2238
2239         if (queue_remove(service->incl_services, removed_service))
2240                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
2241                                                         service->path,
2242                                                         GATT_SERVICE_IFACE,
2243                                                         "Includes");
2244 }
2245
2246 static void unregister_service(void *data)
2247 {
2248         struct service *service = data;
2249         struct btd_gatt_client *client = service->client;
2250
2251         DBG("Removing GATT service: %s", service->path);
2252
2253 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2254         if (service->idle_id)
2255                 g_source_remove(service->idle_id);
2256 #endif
2257
2258         queue_remove_all(service->chrcs, NULL, NULL, unregister_characteristic);
2259         queue_remove_all(service->incl_services, NULL, NULL, NULL);
2260
2261         queue_foreach(client->services, on_service_removed, service);
2262
2263         g_dbus_unregister_interface(btd_get_dbus_connection(), service->path,
2264                                                         GATT_SERVICE_IFACE);
2265 }
2266
2267 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2268 static void notify_service_added(struct service *service)
2269 {
2270         char *svc_path;
2271
2272         if (service == NULL) {
2273                 error("service is NULL");
2274                 return;
2275         }
2276
2277         if (service->path == NULL) {
2278                 error("service->path is NULL");
2279                 return;
2280         }
2281         if (!service->chrcs_ready) {
2282                 error("service is not ready");
2283                 return;
2284         }
2285
2286         svc_path = g_strdup(service->path);
2287
2288         g_dbus_emit_signal(btd_get_dbus_connection(), service->path,
2289                 GATT_SERVICE_IFACE, "GattServiceAdded",
2290                 DBUS_TYPE_STRING, &svc_path,
2291                 DBUS_TYPE_INVALID);
2292
2293         g_free(svc_path);
2294
2295         return;
2296 }
2297
2298 static void notify_chrcs(struct service *service)
2299 {
2300
2301         if (service->chrcs_ready ||
2302                                 !queue_isempty(service->pending_ext_props))
2303                 return;
2304
2305         service->chrcs_ready = true;
2306
2307         g_dbus_emit_property_changed(btd_get_dbus_connection(), service->path,
2308                                                         GATT_SERVICE_IFACE,
2309                                                         "Characteristics");
2310         if (service->primary == true) {
2311                 DBG("Notify Service Added");
2312                 notify_service_added(service);
2313         }
2314 }
2315 #endif
2316
2317 struct export_data {
2318         void *root;
2319         bool failed;
2320 };
2321
2322 static void export_desc(struct gatt_db_attribute *attr, void *user_data)
2323 {
2324         struct descriptor *desc;
2325         struct export_data *data = user_data;
2326         struct characteristic *charac = data->root;
2327
2328         if (data->failed)
2329                 return;
2330
2331         desc = descriptor_create(attr, charac);
2332         if (!desc) {
2333                 data->failed = true;
2334                 return;
2335         }
2336
2337         queue_push_tail(charac->descs, desc);
2338 }
2339
2340 static bool create_descriptors(struct gatt_db_attribute *attr,
2341                                         struct characteristic *charac)
2342 {
2343         struct export_data data;
2344
2345         data.root = charac;
2346         data.failed = false;
2347
2348         gatt_db_service_foreach_desc(attr, export_desc, &data);
2349
2350         return !data.failed;
2351 }
2352
2353 static void export_char(struct gatt_db_attribute *attr, void *user_data)
2354 {
2355         struct characteristic *charac;
2356         struct export_data *data = user_data;
2357         struct service *service = data->root;
2358
2359         if (data->failed)
2360                 return;
2361
2362         charac = characteristic_create(attr, service);
2363         if (!charac)
2364                 goto fail;
2365
2366         if (!create_descriptors(attr, charac)) {
2367                 unregister_characteristic(charac);
2368                 goto fail;
2369         }
2370
2371         queue_push_tail(service->chrcs, charac);
2372
2373 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2374         if (charac->ext_props_handle)
2375                 queue_push_tail(service->pending_ext_props, charac);
2376 #endif
2377
2378         return;
2379
2380 fail:
2381         data->failed = true;
2382 }
2383
2384 static bool create_characteristics(struct gatt_db_attribute *attr,
2385                                                 struct service *service)
2386 {
2387         struct export_data data;
2388
2389         data.root = service;
2390         data.failed = false;
2391
2392         gatt_db_service_foreach_char(attr, export_char, &data);
2393
2394         return !data.failed;
2395 }
2396
2397 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2398 static gboolean set_chrcs_ready(gpointer user_data)
2399 {
2400         struct service *service = user_data;
2401
2402         service->idle_id = 0;
2403         notify_chrcs(service);
2404
2405         return FALSE;
2406 }
2407 #endif
2408 static void export_service(struct gatt_db_attribute *attr, void *user_data)
2409 {
2410         struct btd_gatt_client *client = user_data;
2411         struct service *service;
2412
2413         if (gatt_db_service_get_claimed(attr))
2414                 return;
2415
2416         service = service_create(attr, client);
2417         if (!service)
2418                 return;
2419
2420         if (!create_characteristics(attr, service)) {
2421                 error("Exporting characteristics failed");
2422                 unregister_service(service);
2423                 return;
2424         }
2425
2426         queue_push_tail(client->services, service);
2427
2428 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2429         /*
2430          * Asynchronously update the "Characteristics" property of the service.
2431          * If there are any pending reads to obtain the value of the "Extended
2432          * Properties" descriptor then wait until they are complete.
2433          */
2434         if (!service->chrcs_ready && queue_isempty(service->pending_ext_props))
2435                 service->idle_id = g_idle_add(set_chrcs_ready, service);
2436 #endif
2437 }
2438
2439 static bool match_service_handle(const void *a, const void *b)
2440 {
2441         const struct service *service = a;
2442         uint16_t start_handle = PTR_TO_UINT(b);
2443
2444         return service->start_handle == start_handle;
2445 }
2446
2447 struct update_incl_data {
2448         struct service *service;
2449         bool changed;
2450 };
2451
2452 static void update_included_service(struct gatt_db_attribute *attrib,
2453                                                         void *user_data)
2454 {
2455         struct update_incl_data *update_data = user_data;
2456         struct btd_gatt_client *client = update_data->service->client;
2457         struct service *service = update_data->service;
2458         struct service *incl_service;
2459         uint16_t start_handle;
2460
2461         gatt_db_attribute_get_incl_data(attrib, NULL, &start_handle, NULL);
2462
2463         incl_service = queue_find(client->services, match_service_handle,
2464                                                 UINT_TO_PTR(start_handle));
2465
2466         if (!incl_service)
2467                 return;
2468
2469         /* Check if service is already on list */
2470         if (queue_find(service->incl_services, NULL, incl_service))
2471                 return;
2472
2473         queue_push_tail(service->incl_services, incl_service);
2474         update_data->changed = true;
2475 }
2476
2477 static void update_included_services(void *data, void *user_data)
2478 {
2479         struct btd_gatt_client *client = user_data;
2480         struct service *service = data;
2481         struct gatt_db_attribute *attr;
2482         struct update_incl_data inc_data = {
2483                 .changed = false,
2484                 .service = service,
2485         };
2486
2487         attr = gatt_db_get_attribute(client->db, service->start_handle);
2488         gatt_db_service_foreach_incl(attr, update_included_service, &inc_data);
2489
2490         if (inc_data.changed)
2491                 g_dbus_emit_property_changed(btd_get_dbus_connection(),
2492                                                         service->path,
2493                                                         GATT_SERVICE_IFACE,
2494                                                         "Includes");
2495 }
2496
2497 static void create_services(struct btd_gatt_client *client)
2498 {
2499         DBG("Exporting objects for GATT services: %s", client->devaddr);
2500
2501         gatt_db_foreach_service(client->db, NULL, export_service, client);
2502
2503         queue_foreach(client->services, update_included_services, client);
2504 }
2505
2506 struct btd_gatt_client *btd_gatt_client_new(struct btd_device *device)
2507 {
2508         struct btd_gatt_client *client;
2509         struct gatt_db *db;
2510
2511         if (!device)
2512                 return NULL;
2513
2514         db = btd_device_get_gatt_db(device);
2515         if (!db)
2516                 return NULL;
2517
2518         client = new0(struct btd_gatt_client, 1);
2519         client->services = queue_new();
2520         client->all_notify_clients = queue_new();
2521         client->ios = queue_new();
2522         client->device = device;
2523         ba2str(device_get_address(device), client->devaddr);
2524
2525         client->db = gatt_db_ref(db);
2526
2527         return client;
2528 }
2529
2530 void btd_gatt_client_destroy(struct btd_gatt_client *client)
2531 {
2532         if (!client)
2533                 return;
2534
2535 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2536         if (client->wait_charcs_id)
2537                 g_source_remove(client->wait_charcs_id);
2538 #endif
2539         queue_destroy(client->services, unregister_service);
2540         queue_destroy(client->all_notify_clients, NULL);
2541         queue_destroy(client->ios, NULL);
2542         bt_gatt_client_unref(client->gatt);
2543         gatt_db_unref(client->db);
2544         free(client);
2545 }
2546
2547 static void register_notify(void *data, void *user_data)
2548 {
2549         struct notify_client *notify_client = data;
2550         struct btd_gatt_client *client = user_data;
2551         struct async_dbus_op *op;
2552
2553         DBG("Re-register subscribed notification client");
2554
2555         op = new0(struct async_dbus_op, 1);
2556         op->data = notify_client;
2557
2558         notify_client->notify_id = bt_gatt_client_register_notify(client->gatt,
2559                                         notify_client->chrc->value_handle,
2560                                         register_notify_cb, notify_cb,
2561                                         op, async_dbus_op_free);
2562         if (notify_client->notify_id)
2563                 return;
2564
2565         async_dbus_op_free(op);
2566
2567         DBG("Failed to re-register notification client");
2568
2569         queue_remove(notify_client->chrc->notify_clients, notify_client);
2570         queue_remove(client->all_notify_clients, notify_client);
2571
2572         notify_client_free(notify_client);
2573 }
2574
2575 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2576 static void check_chrcs_ready(void *data, void *user_data)
2577 {
2578         gboolean *chrcs_ready = user_data;
2579         struct service *service = data;
2580
2581         /*
2582         * Return FALSE if charcteristics are not ready or if there is
2583         * any pending request to read char. extended properties exist.
2584         */
2585         if (!service->chrcs_ready ||
2586                 !queue_isempty(service->pending_ext_props))
2587                 *chrcs_ready = FALSE;
2588 }
2589
2590 static gboolean check_all_chrcs_ready(gpointer user_data)
2591 {
2592         struct btd_gatt_client *client = user_data;
2593         gboolean all_chrcs_ready = TRUE;
2594         static int count = 0;
2595
2596         queue_foreach(client->services, check_chrcs_ready, &all_chrcs_ready);
2597
2598         /*
2599         * By adding below condition, forcing to call check_chrcs_ready()
2600         * function to check whether all char./extended properties are ready.
2601         * Above function would be called max. for 500 times (Assuming more
2602         * no of services). Emit signal only when all characteristics are ready.
2603         */
2604         if (all_chrcs_ready == FALSE && count < 500) {
2605                 count++;
2606                 return TRUE;
2607         }
2608
2609         /*
2610         * There are chances when all of the primary services are not found,
2611         * instead service changed is received while reading REQs in progress,
2612         * so emit signal after service changed operation is completed (if any).
2613         */
2614         if (bt_gatt_client_svc_changed_received(client->gatt))
2615                 return TRUE;
2616
2617         device_set_gatt_connected(client->device, TRUE);
2618
2619         client->wait_charcs_id = 0;
2620
2621         count = 0;
2622
2623         return FALSE;
2624 }
2625 #endif
2626
2627 void btd_gatt_client_ready(struct btd_gatt_client *client)
2628 {
2629         if (!client)
2630                 return;
2631
2632         if (!client->gatt) {
2633                 struct bt_gatt_client *gatt;
2634
2635                 gatt = btd_device_get_gatt_client(client->device);
2636                 client->gatt = bt_gatt_client_clone(gatt);
2637                 if (!client->gatt) {
2638                         error("GATT client not initialized");
2639                         return;
2640                 }
2641         }
2642
2643         client->ready = true;
2644
2645         DBG("GATT client ready");
2646
2647         create_services(client);
2648
2649         DBG("Features 0x%02x", client->features);
2650
2651         if (!client->features) {
2652                 client->features = bt_gatt_client_get_features(client->gatt);
2653                 DBG("Update Features 0x%02x", client->features);
2654                 if (client->features & BT_GATT_CHRC_CLI_FEAT_EATT)
2655                        btd_gatt_client_eatt_connect(client);
2656         }
2657
2658 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2659         /*
2660          * In case of more number of services and services having
2661          * characteristics extended properties; GattConnected signal
2662          * should be emitted only after all the characteristics are ready.
2663          * This piece of code checks all the characteristics periodically and
2664          * emit the signal if characteristics are ready.
2665          */
2666         if (client->wait_charcs_id > 0)
2667                 g_source_remove(client->wait_charcs_id);
2668
2669         client->wait_charcs_id = g_timeout_add(10,
2670                         check_all_chrcs_ready, client);
2671 #endif
2672 }
2673
2674
2675 static void eatt_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
2676 {
2677         struct btd_gatt_client *client = user_data;
2678
2679         if (gerr)
2680                 return;
2681
2682         device_attach_att(client->device, io);
2683 }
2684
2685 void btd_gatt_client_eatt_connect(struct btd_gatt_client *client)
2686 {
2687         struct bt_att *att = bt_gatt_client_get_att(client->gatt);
2688         struct btd_device *dev = client->device;
2689         struct btd_adapter *adapter = device_get_adapter(dev);
2690         GIOChannel *io;
2691         GError *gerr = NULL;
2692         char addr[18];
2693         int i;
2694
2695         if (!(client->features & BT_GATT_CHRC_CLI_FEAT_EATT))
2696                 return;
2697         if (bt_att_get_channels(att) == btd_opts.gatt_channels)
2698                 return;
2699
2700         ba2str(device_get_address(dev), addr);
2701
2702         for (i = bt_att_get_channels(att); i < btd_opts.gatt_channels; i++) {
2703                 int defer_timeout = i + 1 < btd_opts.gatt_channels ? 1 : 0;
2704
2705                 DBG("Connection attempt to: %s defer %s", addr,
2706                                         defer_timeout ? "true" : "false");
2707
2708                 /* Attempt to connect using the Ext-Flowctl */
2709                 io = bt_io_connect(eatt_connect_cb, client, NULL, &gerr,
2710                                         BT_IO_OPT_SOURCE_BDADDR,
2711                                         btd_adapter_get_address(adapter),
2712                                         BT_IO_OPT_SOURCE_TYPE,
2713                                         btd_adapter_get_address_type(adapter),
2714                                         BT_IO_OPT_DEST_BDADDR,
2715                                         device_get_address(dev),
2716                                         BT_IO_OPT_DEST_TYPE,
2717                                         device_get_le_address_type(dev),
2718                                         BT_IO_OPT_MODE, BT_IO_MODE_EXT_FLOWCTL,
2719                                         BT_IO_OPT_PSM, BT_ATT_EATT_PSM,
2720                                         BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
2721                                         BT_IO_OPT_MTU, btd_opts.gatt_mtu,
2722                                         BT_IO_OPT_DEFER_TIMEOUT, defer_timeout,
2723                                         BT_IO_OPT_INVALID);
2724                 if (!io) {
2725                         g_error_free(gerr);
2726                         gerr = NULL;
2727                         /* Fallback to legacy LE Mode */
2728                         io = bt_io_connect(eatt_connect_cb, client, NULL, &gerr,
2729                                         BT_IO_OPT_SOURCE_BDADDR,
2730                                         btd_adapter_get_address(adapter),
2731                                         BT_IO_OPT_SOURCE_TYPE,
2732                                         btd_adapter_get_address_type(adapter),
2733                                         BT_IO_OPT_DEST_BDADDR,
2734                                         device_get_address(dev),
2735                                         BT_IO_OPT_DEST_TYPE,
2736                                         device_get_le_address_type(dev),
2737                                         BT_IO_OPT_PSM, BT_ATT_EATT_PSM,
2738                                         BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
2739                                         BT_IO_OPT_MTU, btd_opts.gatt_mtu,
2740                                         BT_IO_OPT_INVALID);
2741                         if (!io) {
2742                                 error("EATT bt_io_connect(%s): %s", addr,
2743                                                         gerr->message);
2744                                 g_error_free(gerr);
2745                                 return;
2746                         }
2747                 }
2748
2749                 g_io_channel_unref(io);
2750         }
2751 }
2752
2753 void btd_gatt_client_connected(struct btd_gatt_client *client)
2754 {
2755         struct bt_gatt_client *gatt;
2756
2757         gatt = btd_device_get_gatt_client(client->device);
2758         if (!gatt) {
2759                 error("GATT client not initialized");
2760                 return;
2761         }
2762
2763         DBG("Device connected.");
2764
2765         bt_gatt_client_unref(client->gatt);
2766 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2767         /* The Client data is not getting updated
2768          * while clone logic is used, because of which
2769          * the notification callbacks and other debug callbacks
2770          * are not getting set properly, untill the clone logic
2771          * is fixed, the ref logic is used */
2772         client->gatt = bt_gatt_client_ref(gatt);
2773 #else
2774         client->gatt = bt_gatt_client_clone(gatt);
2775 #endif
2776         /*
2777          * Services have already been created before. Re-enable notifications
2778          * for any pre-registered notification sessions.
2779          */
2780         queue_foreach(client->all_notify_clients, register_notify, client);
2781 }
2782
2783 void btd_gatt_client_service_added(struct btd_gatt_client *client,
2784                                         struct gatt_db_attribute *attrib)
2785 {
2786         if (!client || !attrib || !client->ready)
2787                 return;
2788
2789         export_service(attrib, client);
2790
2791         queue_foreach(client->services, update_included_services, client);
2792 }
2793
2794 void btd_gatt_client_service_removed(struct btd_gatt_client *client,
2795                                         struct gatt_db_attribute *attrib)
2796 {
2797         uint16_t start_handle, end_handle;
2798
2799         if (!client || !attrib || !client->ready)
2800                 return;
2801
2802         gatt_db_attribute_get_service_handles(attrib, &start_handle,
2803                                                                 &end_handle);
2804
2805         DBG("GATT Services Removed - start: 0x%04x, end: 0x%04x", start_handle,
2806                                                                 end_handle);
2807         queue_remove_all(client->services, match_service_handle,
2808                                                 UINT_TO_PTR(start_handle),
2809                                                 unregister_service);
2810 }
2811
2812 static void clear_notify_id(void *data, void *user_data)
2813 {
2814         struct notify_client *client = data;
2815
2816         client->notify_id = 0;
2817 }
2818
2819 static void client_shutdown(void *data)
2820 {
2821         io_shutdown(data);
2822 }
2823
2824 void btd_gatt_client_disconnected(struct btd_gatt_client *client)
2825 {
2826         if (!client || !client->gatt)
2827                 return;
2828
2829         DBG("Device disconnected. Cleaning up.");
2830
2831 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
2832         if (client->wait_charcs_id) {
2833                 g_source_remove(client->wait_charcs_id);
2834                 client->wait_charcs_id = 0;
2835         }
2836 #endif
2837         queue_remove_all(client->ios, NULL, NULL, client_shutdown);
2838
2839         /*
2840          * TODO: Once GATT over BR/EDR is properly supported, we should pass the
2841          * correct bdaddr_type based on the transport over which GATT is being
2842          * done.
2843          */
2844         queue_foreach(client->all_notify_clients, clear_notify_id, NULL);
2845
2846         bt_gatt_client_unref(client->gatt);
2847         client->gatt = NULL;
2848 }
2849
2850 struct foreach_service_data {
2851         btd_gatt_client_service_path_t func;
2852         void *user_data;
2853 };
2854
2855 static void client_service_foreach(void *data, void *user_data)
2856 {
2857         struct service *service = data;
2858         struct foreach_service_data *foreach_data = user_data;
2859
2860         foreach_data->func(service->path, foreach_data->user_data);
2861 }
2862
2863 void btd_gatt_client_foreach_service(struct btd_gatt_client *client,
2864                                         btd_gatt_client_service_path_t func,
2865                                         void *user_data)
2866 {
2867         struct foreach_service_data data;
2868
2869         if (!client)
2870                 return;
2871
2872         data.func = func;
2873         data.user_data = user_data;
2874
2875         queue_foreach(client->services, client_service_foreach, &data);
2876 }