87e9f7ff8bab946afb8111ce3c971e5cb781a71c
[platform/upstream/bluez.git] / client / gatt.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2014  Intel Corporation. All rights reserved.
7  *
8  *
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <stdio.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <stdbool.h>
20 #include <sys/uio.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25
26 #include <glib.h>
27
28 #include "src/shared/util.h"
29 #include "src/shared/queue.h"
30 #include "src/shared/io.h"
31 #include "src/shared/shell.h"
32 #include "gdbus/gdbus.h"
33 #include "gatt.h"
34
35 #define APP_PATH "/org/bluez/app"
36 #define DEVICE_INTERFACE "org.bluez.Device1"
37 #define PROFILE_INTERFACE "org.bluez.GattProfile1"
38 #define SERVICE_INTERFACE "org.bluez.GattService1"
39 #define CHRC_INTERFACE "org.bluez.GattCharacteristic1"
40 #define DESC_INTERFACE "org.bluez.GattDescriptor1"
41
42 /* String display constants */
43 #define COLORED_NEW     COLOR_GREEN "NEW" COLOR_OFF
44 #define COLORED_CHG     COLOR_YELLOW "CHG" COLOR_OFF
45 #define COLORED_DEL     COLOR_RED "DEL" COLOR_OFF
46
47 #define MAX_ATTR_VAL_LEN        512
48
49 struct desc {
50         struct chrc *chrc;
51         char *path;
52         uint16_t handle;
53         char *uuid;
54         char **flags;
55         size_t value_len;
56         unsigned int max_val_len;
57         uint8_t *value;
58 };
59
60 struct chrc {
61         struct service *service;
62         GDBusProxy *proxy;
63         char *path;
64         uint16_t handle;
65         char *uuid;
66         char **flags;
67         bool notifying;
68         GList *descs;
69         size_t value_len;
70         unsigned int max_val_len;
71         uint8_t *value;
72         uint16_t mtu;
73         struct io *write_io;
74         struct io *notify_io;
75         bool authorization_req;
76 };
77
78 struct service {
79         DBusConnection *conn;
80         GDBusProxy *proxy;
81         char *path;
82         uint16_t handle;
83         char *uuid;
84         bool primary;
85         GList *chrcs;
86         GList *inc;
87 };
88
89 static GList *local_services;
90 static GList *services;
91 static GList *characteristics;
92 static GList *descriptors;
93 static GList *managers;
94 static GList *uuids;
95 static DBusMessage *pending_message = NULL;
96
97 struct sock_io {
98         GDBusProxy *proxy;
99         struct io *io;
100         uint16_t mtu;
101 };
102
103 static struct sock_io write_io;
104 static struct sock_io notify_io;
105
106 static void print_service(struct service *service, const char *description)
107 {
108         const char *text;
109
110         text = bt_uuidstr_to_str(service->uuid);
111         if (!text)
112                 bt_shell_printf("%s%s%s%s Service (Handle 0x%04x)\n\t%s\n\t"
113                                         "%s\n",
114                                         description ? "[" : "",
115                                         description ? : "",
116                                         description ? "] " : "",
117                                         service->primary ? "Primary" :
118                                         "Secondary",
119                                         service->handle, service->path,
120                                         service->uuid);
121         else
122                 bt_shell_printf("%s%s%s%s Service (Handle 0x%04x)\n\t%s\n\t%s"
123                                         "\n\t%s\n",
124                                         description ? "[" : "",
125                                         description ? : "",
126                                         description ? "] " : "",
127                                         service->primary ? "Primary" :
128                                         "Secondary",
129                                         service->handle, service->path,
130                                         service->uuid, text);
131 }
132
133 static void print_inc_service(struct service *service, const char *description)
134 {
135         const char *text;
136
137         text = bt_uuidstr_to_str(service->uuid);
138         if (!text)
139                 bt_shell_printf("%s%s%s%s Included Service (Handle 0x%04x)\n\t"
140                                         "%s\n\t%s\n",
141                                         description ? "[" : "",
142                                         description ? : "",
143                                         description ? "] " : "",
144                                         service->primary ? "Primary" :
145                                         "Secondary",
146                                         service->handle, service->path,
147                                         service->uuid);
148         else
149                 bt_shell_printf("%s%s%s%s Included Service (Handle 0x%04x)\n\t"
150                                         "%s\n\t%s\n\t%s\n",
151                                         description ? "[" : "",
152                                         description ? : "",
153                                         description ? "] " : "",
154                                         service->primary ? "Primary" :
155                                         "Secondary",
156                                         service->handle, service->path,
157                                         service->uuid, text);
158 }
159
160 static void print_service_proxy(GDBusProxy *proxy, const char *description)
161 {
162         struct service service;
163         DBusMessageIter iter;
164         const char *uuid;
165         dbus_bool_t primary;
166
167         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
168                 return;
169
170         dbus_message_iter_get_basic(&iter, &uuid);
171
172         if (g_dbus_proxy_get_property(proxy, "Primary", &iter) == FALSE)
173                 return;
174
175         dbus_message_iter_get_basic(&iter, &primary);
176
177         service.path = (char *) g_dbus_proxy_get_path(proxy);
178         service.uuid = (char *) uuid;
179         service.primary = primary;
180
181         print_service(&service, description);
182 }
183
184 void gatt_add_service(GDBusProxy *proxy)
185 {
186         services = g_list_append(services, proxy);
187
188         print_service_proxy(proxy, COLORED_NEW);
189 }
190
191 static struct service *remove_service_by_proxy(struct GDBusProxy *proxy)
192 {
193         GList *l;
194
195         for (l = local_services; l; l = g_list_next(l)) {
196                 struct service *service = l->data;
197
198                 if (service->proxy == proxy) {
199                         local_services = g_list_delete_link(local_services, l);
200                         return service;
201                 }
202         }
203
204         return NULL;
205 }
206
207 void gatt_remove_service(GDBusProxy *proxy)
208 {
209         struct service *service;
210         GList *l;
211
212         l = g_list_find(services, proxy);
213         if (!l)
214                 return;
215
216         services = g_list_delete_link(services, l);
217
218         print_service_proxy(proxy, COLORED_DEL);
219
220         service = remove_service_by_proxy(proxy);
221         if (service)
222                 g_dbus_unregister_interface(service->conn, service->path,
223                                                 SERVICE_INTERFACE);
224 }
225
226 static void print_chrc(struct chrc *chrc, const char *description)
227 {
228         const char *text;
229
230         text = bt_uuidstr_to_str(chrc->uuid);
231         if (!text)
232                 bt_shell_printf("%s%s%sCharacteristic (Handle 0x%04x)\n\t%s\n\t"
233                                         "%s\n",
234                                         description ? "[" : "",
235                                         description ? : "",
236                                         description ? "] " : "",
237                                         chrc->handle, chrc->path, chrc->uuid);
238         else
239                 bt_shell_printf("%s%s%sCharacteristic (Handle 0x%04x)\n\t%s\n\t"
240                                         "%s\n\t%s\n",
241                                         description ? "[" : "",
242                                         description ? : "",
243                                         description ? "] " : "",
244                                         chrc->handle, chrc->path, chrc->uuid,
245                                         text);
246 }
247
248 static void print_characteristic(GDBusProxy *proxy, const char *description)
249 {
250         struct chrc chrc;
251         DBusMessageIter iter;
252         const char *uuid;
253
254         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
255                 return;
256
257         dbus_message_iter_get_basic(&iter, &uuid);
258
259         chrc.path = (char *) g_dbus_proxy_get_path(proxy);
260         chrc.uuid = (char *) uuid;
261
262         print_chrc(&chrc, description);
263 }
264
265 static gboolean chrc_is_child(GDBusProxy *characteristic)
266 {
267         DBusMessageIter iter;
268         const char *service;
269
270         if (!g_dbus_proxy_get_property(characteristic, "Service", &iter))
271                 return FALSE;
272
273         dbus_message_iter_get_basic(&iter, &service);
274
275         return g_dbus_proxy_lookup(services, NULL, service,
276                                         "org.bluez.GattService1") != NULL;
277 }
278
279 void gatt_add_characteristic(GDBusProxy *proxy)
280 {
281         if (!chrc_is_child(proxy))
282                 return;
283
284         characteristics = g_list_append(characteristics, proxy);
285
286         print_characteristic(proxy, COLORED_NEW);
287 }
288
289 static void notify_io_destroy(void)
290 {
291         io_destroy(notify_io.io);
292         memset(&notify_io, 0, sizeof(notify_io));
293 }
294
295 static void write_io_destroy(void)
296 {
297         io_destroy(write_io.io);
298         memset(&write_io, 0, sizeof(write_io));
299 }
300
301 void gatt_remove_characteristic(GDBusProxy *proxy)
302 {
303         GList *l;
304
305         l = g_list_find(characteristics, proxy);
306         if (!l)
307                 return;
308
309         characteristics = g_list_delete_link(characteristics, l);
310
311         print_characteristic(proxy, COLORED_DEL);
312
313         if (write_io.proxy == proxy)
314                 write_io_destroy();
315         else if (notify_io.proxy == proxy)
316                 notify_io_destroy();
317 }
318
319 static void print_desc(struct desc *desc, const char *description)
320 {
321         const char *text;
322
323         text = bt_uuidstr_to_str(desc->uuid);
324         if (!text)
325                 bt_shell_printf("%s%s%sDescriptor (Handle 0x%04x)\n\t%s\n\t"
326                                         "%s\n",
327                                         description ? "[" : "",
328                                         description ? : "",
329                                         description ? "] " : "",
330                                         desc->handle, desc->path, desc->uuid);
331         else
332                 bt_shell_printf("%s%s%sDescriptor (Handle 0x%04x)\n\t%s\n\t"
333                                         "%s\n\t%s\n",
334                                         description ? "[" : "",
335                                         description ? : "",
336                                         description ? "] " : "",
337                                         desc->handle, desc->path, desc->uuid,
338                                         text);
339 }
340
341 static void print_descriptor(GDBusProxy *proxy, const char *description)
342 {
343         struct desc desc;
344         DBusMessageIter iter;
345         const char *uuid;
346
347         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
348                 return;
349
350         dbus_message_iter_get_basic(&iter, &uuid);
351
352         desc.path = (char *) g_dbus_proxy_get_path(proxy);
353         desc.uuid = (char *) uuid;
354
355         print_desc(&desc, description);
356 }
357
358 static gboolean descriptor_is_child(GDBusProxy *characteristic)
359 {
360         GList *l;
361         DBusMessageIter iter;
362         const char *service, *path;
363
364         if (!g_dbus_proxy_get_property(characteristic, "Characteristic", &iter))
365                 return FALSE;
366
367         dbus_message_iter_get_basic(&iter, &service);
368
369         for (l = characteristics; l; l = g_list_next(l)) {
370                 GDBusProxy *proxy = l->data;
371
372                 path = g_dbus_proxy_get_path(proxy);
373
374                 if (!strcmp(path, service))
375                         return TRUE;
376         }
377
378         return FALSE;
379 }
380
381 void gatt_add_descriptor(GDBusProxy *proxy)
382 {
383         if (!descriptor_is_child(proxy))
384                 return;
385
386         descriptors = g_list_append(descriptors, proxy);
387
388         print_descriptor(proxy, COLORED_NEW);
389 }
390
391 void gatt_remove_descriptor(GDBusProxy *proxy)
392 {
393         GList *l;
394
395         l = g_list_find(descriptors, proxy);
396         if (!l)
397                 return;
398
399         descriptors = g_list_delete_link(descriptors, l);
400
401         print_descriptor(proxy, COLORED_DEL);
402 }
403
404 static void list_attributes(const char *path, GList *source)
405 {
406         GList *l;
407
408         for (l = source; l; l = g_list_next(l)) {
409                 GDBusProxy *proxy = l->data;
410                 const char *proxy_path;
411
412                 proxy_path = g_dbus_proxy_get_path(proxy);
413
414                 if (!g_str_has_prefix(proxy_path, path))
415                         continue;
416
417                 if (source == services) {
418                         print_service_proxy(proxy, NULL);
419                         list_attributes(proxy_path, characteristics);
420                 } else if (source == characteristics) {
421                         print_characteristic(proxy, NULL);
422                         list_attributes(proxy_path, descriptors);
423                 } else if (source == descriptors)
424                         print_descriptor(proxy, NULL);
425         }
426 }
427
428 static void list_descs(GList *descs)
429 {
430         GList *l;
431
432         for (l = descs; l; l = g_list_next(l)) {
433                 struct desc *desc = l->data;
434
435                 print_desc(desc, NULL);
436         }
437 }
438
439 static void list_chrcs(GList *chrcs)
440 {
441         GList *l;
442
443         for (l = chrcs; l; l = g_list_next(l)) {
444                 struct chrc *chrc = l->data;
445
446                 print_chrc(chrc, NULL);
447
448                 list_descs(chrc->descs);
449         }
450 }
451
452 static void list_services(void)
453 {
454         GList *l;
455
456         for (l = local_services; l; l = g_list_next(l)) {
457                 struct service *service = l->data;
458
459                 print_service(service, NULL);
460
461                 list_chrcs(service->chrcs);
462         }
463 }
464
465 void gatt_list_attributes(const char *path)
466 {
467         if (path && !strcmp(path, "local")) {
468                 list_services();
469                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
470         }
471
472         list_attributes(path, services);
473         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
474 }
475
476 static GDBusProxy *select_attribute(const char *path)
477 {
478         GDBusProxy *proxy;
479
480         proxy = g_dbus_proxy_lookup(services, NULL, path,
481                                         "org.bluez.GattService1");
482         if (proxy)
483                 return proxy;
484
485         proxy = g_dbus_proxy_lookup(characteristics, NULL, path,
486                                         "org.bluez.GattCharacteristic1");
487         if (proxy)
488                 return proxy;
489
490         return g_dbus_proxy_lookup(descriptors, NULL, path,
491                                         "org.bluez.GattDescriptor1");
492 }
493
494 static GDBusProxy *select_proxy_by_uuid(GDBusProxy *parent, const char *uuid,
495                                         GList *source)
496 {
497         GList *l;
498         const char *value;
499         DBusMessageIter iter;
500
501         for (l = source; l; l = g_list_next(l)) {
502                 GDBusProxy *proxy = l->data;
503
504                 if (parent && !g_str_has_prefix(g_dbus_proxy_get_path(proxy),
505                                                 g_dbus_proxy_get_path(parent)))
506                         continue;
507
508                 if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
509                         continue;
510
511                 dbus_message_iter_get_basic(&iter, &value);
512
513                 if (strcasecmp(uuid, value) == 0)
514                         return proxy;
515
516                 if (strlen(uuid) == 4 && !strncasecmp(value + 4, uuid, 4))
517                         return proxy;
518         }
519
520         return NULL;
521 }
522
523 static GDBusProxy *select_attribute_by_uuid(GDBusProxy *parent,
524                                                         const char *uuid)
525 {
526         GDBusProxy *proxy;
527
528         proxy = select_proxy_by_uuid(parent, uuid, services);
529         if (proxy)
530                 return proxy;
531
532         proxy = select_proxy_by_uuid(parent, uuid, characteristics);
533         if (proxy)
534                 return proxy;
535
536         return select_proxy_by_uuid(parent, uuid, descriptors);
537 }
538
539 GDBusProxy *gatt_select_attribute(GDBusProxy *parent, const char *arg)
540 {
541         if (arg[0] == '/')
542                 return select_attribute(arg);
543
544         if (parent) {
545                 GDBusProxy *proxy = select_attribute_by_uuid(parent, arg);
546                 if (proxy)
547                         return proxy;
548         }
549
550         return select_attribute_by_uuid(NULL, arg);
551 }
552
553 static char *attribute_generator(const char *text, int state, GList *source)
554 {
555         static int index;
556
557         if (!state) {
558                 index = 0;
559         }
560
561         return g_dbus_proxy_path_lookup(source, &index, text);
562 }
563
564 char *gatt_attribute_generator(const char *text, int state)
565 {
566         static GList *list = NULL;
567
568         if (!state) {
569                 GList *list1;
570
571                 if (list) {
572                         g_list_free(list);
573                         list = NULL;
574                 }
575
576                 list1 = g_list_copy(characteristics);
577                 list1 = g_list_concat(list1, g_list_copy(descriptors));
578
579                 list = g_list_copy(services);
580                 list = g_list_concat(list, list1);
581         }
582
583         return attribute_generator(text, state, list);
584 }
585
586 static void read_reply(DBusMessage *message, void *user_data)
587 {
588         DBusError error;
589         DBusMessageIter iter, array;
590         uint8_t *value;
591         int len;
592
593         dbus_error_init(&error);
594
595         if (dbus_set_error_from_message(&error, message) == TRUE) {
596                 bt_shell_printf("Failed to read: %s\n", error.name);
597                 dbus_error_free(&error);
598                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
599         }
600
601         dbus_message_iter_init(message, &iter);
602
603         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
604                 bt_shell_printf("Invalid response to read\n");
605                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
606         }
607
608         dbus_message_iter_recurse(&iter, &array);
609         dbus_message_iter_get_fixed_array(&array, &value, &len);
610
611         if (len < 0) {
612                 bt_shell_printf("Unable to parse value\n");
613                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
614         }
615
616         bt_shell_hexdump(value, len);
617
618         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
619 }
620
621 static void read_setup(DBusMessageIter *iter, void *user_data)
622 {
623         DBusMessageIter dict;
624         uint16_t *offset = user_data;
625
626         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
627                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
628                                         DBUS_TYPE_STRING_AS_STRING
629                                         DBUS_TYPE_VARIANT_AS_STRING
630                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
631                                         &dict);
632
633         g_dbus_dict_append_entry(&dict, "offset", DBUS_TYPE_UINT16, offset);
634
635         dbus_message_iter_close_container(iter, &dict);
636 }
637
638 static void read_attribute(GDBusProxy *proxy, uint16_t offset)
639 {
640         if (g_dbus_proxy_method_call(proxy, "ReadValue", read_setup, read_reply,
641                                                 &offset, NULL) == FALSE) {
642                 bt_shell_printf("Failed to read\n");
643                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
644         }
645
646         bt_shell_printf("Attempting to read %s\n", g_dbus_proxy_get_path(proxy));
647 }
648
649 void gatt_read_attribute(GDBusProxy *proxy, int argc, char *argv[])
650 {
651         const char *iface;
652         uint16_t offset = 0;
653
654         iface = g_dbus_proxy_get_interface(proxy);
655         if (!strcmp(iface, "org.bluez.GattCharacteristic1") ||
656                                 !strcmp(iface, "org.bluez.GattDescriptor1")) {
657
658                 if (argc == 2)
659                         offset = atoi(argv[1]);
660
661                 read_attribute(proxy, offset);
662                 return;
663         }
664
665         bt_shell_printf("Unable to read attribute %s\n",
666                                                 g_dbus_proxy_get_path(proxy));
667         return bt_shell_noninteractive_quit(EXIT_FAILURE);
668 }
669
670 static void write_reply(DBusMessage *message, void *user_data)
671 {
672         DBusError error;
673
674         dbus_error_init(&error);
675
676         if (dbus_set_error_from_message(&error, message) == TRUE) {
677                 bt_shell_printf("Failed to write: %s\n", error.name);
678                 dbus_error_free(&error);
679                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
680         }
681
682         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
683 }
684
685 struct write_attribute_data {
686         DBusMessage *msg;
687         struct iovec iov;
688         char *type;
689         uint16_t offset;
690 };
691
692 static void write_setup(DBusMessageIter *iter, void *user_data)
693 {
694         struct write_attribute_data *wd = user_data;
695         DBusMessageIter array, dict;
696
697         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
698         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
699                                                 &wd->iov.iov_base,
700                                                 wd->iov.iov_len);
701         dbus_message_iter_close_container(iter, &array);
702
703         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
704                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
705                                         DBUS_TYPE_STRING_AS_STRING
706                                         DBUS_TYPE_VARIANT_AS_STRING
707                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
708                                         &dict);
709
710         if (wd->type)
711                 g_dbus_dict_append_entry(&dict, "type", DBUS_TYPE_STRING,
712                                                                 &wd->type);
713
714         g_dbus_dict_append_entry(&dict, "offset", DBUS_TYPE_UINT16,
715                                                                 &wd->offset);
716
717         dbus_message_iter_close_container(iter, &dict);
718 }
719
720 static int sock_send(struct io *io, struct iovec *iov, size_t iovlen)
721 {
722         struct msghdr msg;
723         int ret;
724
725         memset(&msg, 0, sizeof(msg));
726         msg.msg_iov = iov;
727         msg.msg_iovlen = iovlen;
728
729         ret = sendmsg(io_get_fd(io), &msg, MSG_NOSIGNAL);
730         if (ret < 0) {
731                 ret = -errno;
732                 bt_shell_printf("sendmsg: %s", strerror(-ret));
733         }
734
735         return ret;
736 }
737
738 static void write_attribute(GDBusProxy *proxy,
739                                 struct write_attribute_data *data)
740 {
741         /* Write using the fd if it has been acquired and fit the MTU */
742         if (proxy == write_io.proxy &&
743                         (write_io.io && write_io.mtu >= data->iov.iov_len)) {
744                 bt_shell_printf("Attempting to write fd %d\n",
745                                                 io_get_fd(write_io.io));
746                 if (sock_send(write_io.io, &data->iov, 1) < 0) {
747                         bt_shell_printf("Failed to write: %s", strerror(errno));
748                         return bt_shell_noninteractive_quit(EXIT_FAILURE);
749                 }
750                 return;
751         }
752
753         if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup,
754                                         write_reply, data, NULL) == FALSE) {
755                 bt_shell_printf("Failed to write\n");
756                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
757         }
758
759         bt_shell_printf("Attempting to write %s\n",
760                                         g_dbus_proxy_get_path(proxy));
761 }
762
763 static uint8_t *str2bytearray(char *arg, size_t *val_len)
764 {
765         uint8_t value[MAX_ATTR_VAL_LEN];
766         char *entry;
767         unsigned int i;
768
769         for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) {
770                 long int val;
771                 char *endptr = NULL;
772
773                 if (*entry == '\0')
774                         continue;
775
776                 if (i >= G_N_ELEMENTS(value)) {
777                         bt_shell_printf("Too much data\n");
778                         return NULL;
779                 }
780
781                 val = strtol(entry, &endptr, 0);
782                 if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
783                         bt_shell_printf("Invalid value at index %d\n", i);
784                         return NULL;
785                 }
786
787                 value[i] = val;
788         }
789
790         *val_len = i;
791
792         return g_memdup(value, i);
793 }
794
795 void gatt_write_attribute(GDBusProxy *proxy, int argc, char *argv[])
796 {
797         const char *iface;
798         struct write_attribute_data data;
799
800         memset(&data, 0, sizeof(data));
801
802         iface = g_dbus_proxy_get_interface(proxy);
803         if (!strcmp(iface, "org.bluez.GattCharacteristic1") ||
804                                 !strcmp(iface, "org.bluez.GattDescriptor1")) {
805                 data.iov.iov_base = str2bytearray(argv[1], &data.iov.iov_len);
806
807                 if (argc > 2)
808                         data.offset = atoi(argv[2]);
809
810                 if (argc > 3)
811                         data.type = argv[3];
812
813                 write_attribute(proxy, &data);
814                 return;
815         }
816
817         bt_shell_printf("Unable to write attribute %s\n",
818                                                 g_dbus_proxy_get_path(proxy));
819
820         return bt_shell_noninteractive_quit(EXIT_FAILURE);
821 }
822
823 static bool sock_read(struct io *io, void *user_data)
824 {
825         struct chrc *chrc = user_data;
826         struct msghdr msg;
827         struct iovec iov;
828         uint8_t buf[MAX_ATTR_VAL_LEN];
829         int fd = io_get_fd(io);
830         ssize_t bytes_read;
831
832         if (io != notify_io.io && !chrc)
833                 return true;
834
835         iov.iov_base = buf;
836         iov.iov_len = sizeof(buf);
837
838         memset(&msg, 0, sizeof(msg));
839         msg.msg_iov = &iov;
840         msg.msg_iovlen = 1;
841
842         bytes_read = recvmsg(fd, &msg, MSG_DONTWAIT);
843         if (bytes_read < 0) {
844                 bt_shell_printf("recvmsg: %s", strerror(errno));
845                 return false;
846         }
847
848         if (!bytes_read)
849                 return false;
850
851         if (chrc)
852                 bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) "
853                                 "written:\n", chrc->path,
854                                 bt_uuidstr_to_str(chrc->uuid));
855         else
856                 bt_shell_printf("[" COLORED_CHG "] %s Notification:\n",
857                                 g_dbus_proxy_get_path(notify_io.proxy));
858
859         bt_shell_hexdump(buf, bytes_read);
860
861         return true;
862 }
863
864 static bool sock_hup(struct io *io, void *user_data)
865 {
866         struct chrc *chrc = user_data;
867
868         if (chrc) {
869                 bt_shell_printf("Attribute %s %s sock closed\n", chrc->path,
870                                 io == chrc->write_io ? "Write" : "Notify");
871
872                 if (io == chrc->write_io) {
873                         io_destroy(chrc->write_io);
874                         chrc->write_io = NULL;
875                 } else {
876                         io_destroy(chrc->notify_io);
877                         chrc->notify_io = NULL;
878                 }
879
880                 return false;
881         }
882
883         bt_shell_printf("%s closed\n", io == notify_io.io ? "Notify" : "Write");
884
885         if (io == notify_io.io)
886                 notify_io_destroy();
887         else
888                 write_io_destroy();
889
890         return false;
891 }
892
893 static struct io *sock_io_new(int fd, void *user_data)
894 {
895         struct io *io;
896
897         io = io_new(fd);
898
899         io_set_close_on_destroy(io, true);
900
901         io_set_read_handler(io, sock_read, user_data, NULL);
902
903         io_set_disconnect_handler(io, sock_hup, user_data, NULL);
904
905         return io;
906 }
907
908 static void acquire_write_reply(DBusMessage *message, void *user_data)
909 {
910         DBusError error;
911         int fd;
912
913         dbus_error_init(&error);
914
915         if (dbus_set_error_from_message(&error, message) == TRUE) {
916                 bt_shell_printf("Failed to acquire write: %s\n", error.name);
917                 dbus_error_free(&error);
918                 write_io.proxy = NULL;
919                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
920         }
921
922         if (write_io.io)
923                 write_io_destroy();
924
925         if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
926                                         DBUS_TYPE_UINT16, &write_io.mtu,
927                                         DBUS_TYPE_INVALID) == false)) {
928                 bt_shell_printf("Invalid AcquireWrite response\n");
929                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
930         }
931
932         bt_shell_printf("AcquireWrite success: fd %d MTU %u\n", fd,
933                                                                 write_io.mtu);
934
935         write_io.io = sock_io_new(fd, NULL);
936         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
937 }
938
939 static void acquire_setup(DBusMessageIter *iter, void *user_data)
940 {
941         DBusMessageIter dict;
942
943         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
944                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
945                                         DBUS_TYPE_STRING_AS_STRING
946                                         DBUS_TYPE_VARIANT_AS_STRING
947                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
948                                         &dict);
949
950         dbus_message_iter_close_container(iter, &dict);
951 }
952
953 void gatt_acquire_write(GDBusProxy *proxy, const char *arg)
954 {
955         const char *iface;
956
957         iface = g_dbus_proxy_get_interface(proxy);
958         if (strcmp(iface, "org.bluez.GattCharacteristic1")) {
959                 bt_shell_printf("Unable to acquire write: %s not a"
960                                 " characteristic\n",
961                                 g_dbus_proxy_get_path(proxy));
962                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
963         }
964
965         if (g_dbus_proxy_method_call(proxy, "AcquireWrite", acquire_setup,
966                                 acquire_write_reply, NULL, NULL) == FALSE) {
967                 bt_shell_printf("Failed to AcquireWrite\n");
968                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
969         }
970
971         write_io.proxy = proxy;
972 }
973
974 void gatt_release_write(GDBusProxy *proxy, const char *arg)
975 {
976         if (proxy != write_io.proxy || !write_io.io) {
977                 bt_shell_printf("Write not acquired\n");
978                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
979         }
980
981         write_io_destroy();
982
983         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
984 }
985
986 static void acquire_notify_reply(DBusMessage *message, void *user_data)
987 {
988         DBusError error;
989         int fd;
990
991         dbus_error_init(&error);
992
993         if (dbus_set_error_from_message(&error, message) == TRUE) {
994                 bt_shell_printf("Failed to acquire notify: %s\n", error.name);
995                 dbus_error_free(&error);
996                 write_io.proxy = NULL;
997                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
998         }
999
1000         if (notify_io.io) {
1001                 io_destroy(notify_io.io);
1002                 notify_io.io = NULL;
1003         }
1004
1005         notify_io.mtu = 0;
1006
1007         if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
1008                                         DBUS_TYPE_UINT16, &notify_io.mtu,
1009                                         DBUS_TYPE_INVALID) == false)) {
1010                 bt_shell_printf("Invalid AcquireNotify response\n");
1011                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1012         }
1013
1014         bt_shell_printf("AcquireNotify success: fd %d MTU %u\n", fd,
1015                                                                 notify_io.mtu);
1016
1017         notify_io.io = sock_io_new(fd, NULL);
1018
1019         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1020 }
1021
1022 void gatt_acquire_notify(GDBusProxy *proxy, const char *arg)
1023 {
1024         const char *iface;
1025
1026         iface = g_dbus_proxy_get_interface(proxy);
1027         if (strcmp(iface, "org.bluez.GattCharacteristic1")) {
1028                 bt_shell_printf("Unable to acquire notify: %s not a"
1029                                 " characteristic\n",
1030                                 g_dbus_proxy_get_path(proxy));
1031                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1032         }
1033
1034         if (g_dbus_proxy_method_call(proxy, "AcquireNotify", acquire_setup,
1035                                 acquire_notify_reply, NULL, NULL) == FALSE) {
1036                 bt_shell_printf("Failed to AcquireNotify\n");
1037                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1038         }
1039
1040         notify_io.proxy = proxy;
1041 }
1042
1043 void gatt_release_notify(GDBusProxy *proxy, const char *arg)
1044 {
1045         if (proxy != notify_io.proxy || !notify_io.io) {
1046                 bt_shell_printf("Notify not acquired\n");
1047                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1048         }
1049
1050         notify_io_destroy();
1051
1052         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1053 }
1054
1055 static void notify_reply(DBusMessage *message, void *user_data)
1056 {
1057         bool enable = GPOINTER_TO_UINT(user_data);
1058         DBusError error;
1059
1060         dbus_error_init(&error);
1061
1062         if (dbus_set_error_from_message(&error, message) == TRUE) {
1063                 bt_shell_printf("Failed to %s notify: %s\n",
1064                                 enable ? "start" : "stop", error.name);
1065                 dbus_error_free(&error);
1066                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1067         }
1068
1069         bt_shell_printf("Notify %s\n", enable == TRUE ? "started" : "stopped");
1070
1071         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1072 }
1073
1074 static void notify_attribute(GDBusProxy *proxy, bool enable)
1075 {
1076         const char *method;
1077
1078         if (enable == TRUE)
1079                 method = "StartNotify";
1080         else
1081                 method = "StopNotify";
1082
1083         if (g_dbus_proxy_method_call(proxy, method, NULL, notify_reply,
1084                                 GUINT_TO_POINTER(enable), NULL) == FALSE) {
1085                 bt_shell_printf("Failed to %s notify\n",
1086                                 enable ? "start" : "stop");
1087                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1088         }
1089
1090         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1091 }
1092
1093 void gatt_notify_attribute(GDBusProxy *proxy, bool enable)
1094 {
1095         const char *iface;
1096
1097         iface = g_dbus_proxy_get_interface(proxy);
1098         if (!strcmp(iface, "org.bluez.GattCharacteristic1")) {
1099                 notify_attribute(proxy, enable);
1100                 return;
1101         }
1102
1103         bt_shell_printf("Unable to notify attribute %s\n",
1104                                                 g_dbus_proxy_get_path(proxy));
1105
1106         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1107 }
1108
1109 static void register_app_setup(DBusMessageIter *iter, void *user_data)
1110 {
1111         DBusMessageIter opt;
1112         const char *path = "/";
1113
1114         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
1115
1116         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1117                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1118                                         DBUS_TYPE_STRING_AS_STRING
1119                                         DBUS_TYPE_VARIANT_AS_STRING
1120                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1121                                         &opt);
1122         dbus_message_iter_close_container(iter, &opt);
1123
1124 }
1125
1126 static void register_app_reply(DBusMessage *message, void *user_data)
1127 {
1128         DBusError error;
1129
1130         dbus_error_init(&error);
1131
1132         if (dbus_set_error_from_message(&error, message) == TRUE) {
1133                 bt_shell_printf("Failed to register application: %s\n",
1134                                 error.name);
1135                 dbus_error_free(&error);
1136                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1137         }
1138
1139         bt_shell_printf("Application registered\n");
1140
1141         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1142 }
1143
1144 void gatt_add_manager(GDBusProxy *proxy)
1145 {
1146         managers = g_list_append(managers, proxy);
1147 }
1148
1149 void gatt_remove_manager(GDBusProxy *proxy)
1150 {
1151         managers = g_list_remove(managers, proxy);
1152 }
1153
1154 static int match_proxy(const void *a, const void *b)
1155 {
1156         GDBusProxy *proxy1 = (void *) a;
1157         GDBusProxy *proxy2 = (void *) b;
1158
1159         return strcmp(g_dbus_proxy_get_path(proxy1),
1160                                                 g_dbus_proxy_get_path(proxy2));
1161 }
1162
1163 static DBusMessage *release_profile(DBusConnection *conn,
1164                                         DBusMessage *msg, void *user_data)
1165 {
1166         g_dbus_unregister_interface(conn, APP_PATH, PROFILE_INTERFACE);
1167
1168         return dbus_message_new_method_return(msg);
1169 }
1170
1171 static const GDBusMethodTable methods[] = {
1172         { GDBUS_METHOD("Release", NULL, NULL, release_profile) },
1173         { }
1174 };
1175
1176 static gboolean get_uuids(const GDBusPropertyTable *property,
1177                                         DBusMessageIter *iter, void *data)
1178 {
1179         DBusMessageIter entry;
1180         GList *uuid;
1181
1182         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1183                                 DBUS_TYPE_STRING_AS_STRING, &entry);
1184
1185         for (uuid = uuids; uuid; uuid = g_list_next(uuid->next))
1186                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
1187                                                         &uuid->data);
1188
1189         dbus_message_iter_close_container(iter, &entry);
1190
1191         return TRUE;
1192 }
1193
1194 static const GDBusPropertyTable properties[] = {
1195         { "UUIDs", "as", get_uuids },
1196         { }
1197 };
1198
1199 void gatt_register_app(DBusConnection *conn, GDBusProxy *proxy,
1200                                         int argc, char *argv[])
1201 {
1202         GList *l;
1203         int i;
1204
1205         l = g_list_find_custom(managers, proxy, match_proxy);
1206         if (!l) {
1207                 bt_shell_printf("Unable to find GattManager proxy\n");
1208                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1209         }
1210
1211         for (i = 0; i < argc; i++)
1212                 uuids = g_list_append(uuids, g_strdup(argv[i]));
1213
1214         if (uuids) {
1215                 if (g_dbus_register_interface(conn, APP_PATH,
1216                                                 PROFILE_INTERFACE, methods,
1217                                                 NULL, properties, NULL,
1218                                                 NULL) == FALSE) {
1219                         bt_shell_printf("Failed to register application"
1220                                         " object\n");
1221                         return bt_shell_noninteractive_quit(EXIT_FAILURE);
1222                 }
1223         }
1224
1225         if (g_dbus_proxy_method_call(l->data, "RegisterApplication",
1226                                                 register_app_setup,
1227                                                 register_app_reply, NULL,
1228                                                 NULL) == FALSE) {
1229                 bt_shell_printf("Failed register application\n");
1230                 g_dbus_unregister_interface(conn, APP_PATH, PROFILE_INTERFACE);
1231                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1232         }
1233 }
1234
1235 static void unregister_app_reply(DBusMessage *message, void *user_data)
1236 {
1237         DBusConnection *conn = user_data;
1238         DBusError error;
1239
1240         dbus_error_init(&error);
1241
1242         if (dbus_set_error_from_message(&error, message) == TRUE) {
1243                 bt_shell_printf("Failed to unregister application: %s\n",
1244                                 error.name);
1245                 dbus_error_free(&error);
1246                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1247         }
1248
1249         bt_shell_printf("Application unregistered\n");
1250
1251         if (!uuids)
1252                 return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1253
1254         g_list_free_full(uuids, g_free);
1255         uuids = NULL;
1256
1257         g_dbus_unregister_interface(conn, APP_PATH, PROFILE_INTERFACE);
1258
1259         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1260 }
1261
1262 static void unregister_app_setup(DBusMessageIter *iter, void *user_data)
1263 {
1264         const char *path = "/";
1265
1266         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
1267 }
1268
1269 void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy)
1270 {
1271         GList *l;
1272
1273         l = g_list_find_custom(managers, proxy, match_proxy);
1274         if (!l) {
1275                 bt_shell_printf("Unable to find GattManager proxy\n");
1276                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1277         }
1278
1279         if (g_dbus_proxy_method_call(l->data, "UnregisterApplication",
1280                                                 unregister_app_setup,
1281                                                 unregister_app_reply, conn,
1282                                                 NULL) == FALSE) {
1283                 bt_shell_printf("Failed unregister profile\n");
1284                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1285         }
1286 }
1287
1288 static void desc_free(void *data)
1289 {
1290         struct desc *desc = data;
1291
1292         g_free(desc->path);
1293         g_free(desc->uuid);
1294         g_strfreev(desc->flags);
1295         g_free(desc->value);
1296         g_free(desc);
1297 }
1298
1299 static void desc_unregister(void *data)
1300 {
1301         struct desc *desc = data;
1302
1303         print_desc(desc, COLORED_DEL);
1304
1305         g_dbus_unregister_interface(desc->chrc->service->conn, desc->path,
1306                                                 DESC_INTERFACE);
1307 }
1308
1309 static void chrc_free(void *data)
1310 {
1311         struct chrc *chrc = data;
1312
1313         g_list_free_full(chrc->descs, desc_unregister);
1314         g_free(chrc->path);
1315         g_free(chrc->uuid);
1316         g_strfreev(chrc->flags);
1317         g_free(chrc->value);
1318         g_free(chrc);
1319 }
1320
1321 static void chrc_unregister(void *data)
1322 {
1323         struct chrc *chrc = data;
1324
1325         print_chrc(chrc, COLORED_DEL);
1326
1327         g_dbus_unregister_interface(chrc->service->conn, chrc->path,
1328                                                 CHRC_INTERFACE);
1329 }
1330
1331 static void inc_unregister(void *data)
1332 {
1333         char *path = data;
1334
1335         g_free(path);
1336 }
1337
1338 static void service_free(void *data)
1339 {
1340         struct service *service = data;
1341
1342         g_list_free_full(service->chrcs, chrc_unregister);
1343         g_list_free_full(service->inc, inc_unregister);
1344         g_free(service->path);
1345         g_free(service->uuid);
1346         g_free(service);
1347 }
1348
1349 static gboolean service_get_handle(const GDBusPropertyTable *property,
1350                                         DBusMessageIter *iter, void *data)
1351 {
1352         struct service *service = data;
1353
1354         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
1355                                                 &service->handle);
1356
1357         return TRUE;
1358 }
1359
1360 static void service_set_handle(const GDBusPropertyTable *property,
1361                         DBusMessageIter *value, GDBusPendingPropertySet id,
1362                         void *data)
1363 {
1364         struct service *service = data;
1365
1366         if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16) {
1367                 g_dbus_pending_property_error(id, "org.bluez.InvalidArguments",
1368                                         "Invalid arguments in method call");
1369                 return;
1370         }
1371
1372         dbus_message_iter_get_basic(value, &service->handle);
1373
1374         print_service(service, COLORED_CHG);
1375
1376         g_dbus_pending_property_success(id);
1377 }
1378
1379 static gboolean service_get_uuid(const GDBusPropertyTable *property,
1380                                         DBusMessageIter *iter, void *data)
1381 {
1382         struct service *service = data;
1383
1384         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &service->uuid);
1385
1386         return TRUE;
1387 }
1388
1389 static gboolean service_get_primary(const GDBusPropertyTable *property,
1390                                         DBusMessageIter *iter, void *data)
1391 {
1392         struct service *service = data;
1393         dbus_bool_t primary;
1394
1395         primary = service->primary ? TRUE : FALSE;
1396
1397         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &primary);
1398
1399         return TRUE;
1400 }
1401
1402
1403 static gboolean service_get_includes(const GDBusPropertyTable *property,
1404                                         DBusMessageIter *iter, void *data)
1405 {
1406         DBusMessageIter array;
1407         struct service *service = data;
1408         char *inc  = NULL;
1409         GList *l;
1410
1411         if (service->inc) {
1412                 for (l =  service->inc ; l; l = g_list_next(l)) {
1413
1414                         inc = l->data;
1415                         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1416                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
1417
1418                         dbus_message_iter_append_basic(&array,
1419                                 DBUS_TYPE_OBJECT_PATH, &inc);
1420
1421                 }
1422
1423                 dbus_message_iter_close_container(iter, &array);
1424
1425                 return TRUE;
1426         }
1427
1428         return FALSE;
1429
1430 }
1431
1432 static gboolean service_exist_includes(const GDBusPropertyTable *property,
1433                                                         void *data)
1434 {
1435         struct service *service = data;
1436
1437         if (service->inc)
1438                 return TRUE;
1439         else
1440                 return FALSE;
1441
1442 }
1443
1444
1445 static const GDBusPropertyTable service_properties[] = {
1446         { "Handle", "q", service_get_handle, service_set_handle },
1447         { "UUID", "s", service_get_uuid },
1448         { "Primary", "b", service_get_primary },
1449         { "Includes", "ao", service_get_includes,
1450                 NULL,   service_exist_includes },
1451         { }
1452 };
1453
1454 static void service_set_primary(const char *input, void *user_data)
1455 {
1456         struct service *service = user_data;
1457
1458         if (!strcmp(input, "yes"))
1459                 service->primary = true;
1460         else if (!strcmp(input, "no")) {
1461                 service->primary = false;
1462         } else {
1463                 bt_shell_printf("Invalid option: %s\n", input);
1464                 local_services = g_list_remove(local_services, service);
1465                 print_service(service, COLORED_DEL);
1466                 g_dbus_unregister_interface(service->conn, service->path,
1467                                                 SERVICE_INTERFACE);
1468         }
1469 }
1470
1471 void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
1472                                                 int argc, char *argv[])
1473 {
1474         struct service *service;
1475         bool primary = true;
1476
1477         service = g_new0(struct service, 1);
1478         service->conn = conn;
1479         service->uuid = g_strdup(argv[1]);
1480         service->path = g_strdup_printf("%s/service%u", APP_PATH,
1481                                         g_list_length(local_services));
1482         service->primary = primary;
1483
1484         if (argc > 2)
1485                 service->handle = atoi(argv[2]);
1486
1487         if (g_dbus_register_interface(conn, service->path,
1488                                         SERVICE_INTERFACE, NULL, NULL,
1489                                         service_properties, service,
1490                                         service_free) == FALSE) {
1491                 bt_shell_printf("Failed to register service object\n");
1492                 service_free(service);
1493                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1494         }
1495
1496         print_service(service, COLORED_NEW);
1497
1498         local_services = g_list_append(local_services, service);
1499
1500         bt_shell_prompt_input(service->path, "Primary (yes/no):",
1501                  service_set_primary, service);
1502
1503         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1504 }
1505
1506 static struct service *service_find(const char *pattern)
1507 {
1508         GList *l;
1509
1510         for (l = local_services; l; l = g_list_next(l)) {
1511                 struct service *service = l->data;
1512
1513                 /* match object path */
1514                 if (!strcmp(service->path, pattern))
1515                         return service;
1516
1517                 /* match UUID */
1518                 if (!strcmp(service->uuid, pattern))
1519                         return service;
1520         }
1521
1522         return NULL;
1523 }
1524
1525 void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
1526                                                 int argc, char *argv[])
1527 {
1528         struct service *service;
1529
1530         service = service_find(argv[1]);
1531         if (!service) {
1532                 bt_shell_printf("Failed to unregister service object\n");
1533                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1534         }
1535
1536         local_services = g_list_remove(local_services, service);
1537
1538         print_service(service, COLORED_DEL);
1539
1540         g_dbus_unregister_interface(service->conn, service->path,
1541                                                 SERVICE_INTERFACE);
1542
1543         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1544 }
1545
1546 static char *inc_find(struct service  *serv, char *path)
1547 {
1548         GList *lc;
1549
1550         for (lc = serv->inc; lc; lc =  g_list_next(lc)) {
1551                 char *incp = lc->data;
1552                 /* match object path */
1553                 if (!strcmp(incp, path))
1554                         return incp;
1555         }
1556
1557         return NULL;
1558 }
1559
1560 void gatt_register_include(DBusConnection *conn, GDBusProxy *proxy,
1561                                         int argc, char *argv[])
1562 {
1563         struct service *service, *inc_service;
1564         char *inc_path;
1565
1566         if (!local_services) {
1567                 bt_shell_printf("No service registered\n");
1568                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1569         }
1570
1571         service = g_list_last(local_services)->data;
1572
1573
1574         inc_service = service_find(argv[1]);
1575         if (!inc_service) {
1576                 bt_shell_printf("Failed to find  service object\n");
1577                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1578         }
1579
1580         inc_path = g_strdup(service->path);
1581
1582         inc_service->inc = g_list_append(inc_service->inc, inc_path);
1583
1584         print_service(inc_service, COLORED_NEW);
1585         print_inc_service(service, COLORED_NEW);
1586
1587         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1588 }
1589
1590 void gatt_unregister_include(DBusConnection *conn, GDBusProxy *proxy,
1591                                                 int argc, char *argv[])
1592 {
1593         struct service *ser_inc, *service;
1594         char *path = NULL;
1595
1596         service = service_find(argv[1]);
1597         if (!service) {
1598                 bt_shell_printf("Failed to unregister include service"
1599                                                         " object\n");
1600                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1601         }
1602
1603         ser_inc = service_find(argv[2]);
1604         if (!ser_inc) {
1605                 bt_shell_printf("Failed to find include service object\n");
1606                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
1607         }
1608
1609         path = inc_find(service, ser_inc->path);
1610         if (path) {
1611                 service->inc = g_list_remove(service->inc, path);
1612                 inc_unregister(path);
1613         }
1614
1615         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
1616 }
1617
1618 static gboolean chrc_get_handle(const GDBusPropertyTable *property,
1619                                         DBusMessageIter *iter, void *data)
1620 {
1621         struct chrc *chrc = data;
1622
1623         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &chrc->handle);
1624
1625         return TRUE;
1626 }
1627
1628 static void chrc_set_handle(const GDBusPropertyTable *property,
1629                         DBusMessageIter *value, GDBusPendingPropertySet id,
1630                         void *data)
1631 {
1632         struct chrc *chrc = data;
1633
1634         if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16) {
1635                 g_dbus_pending_property_error(id, "org.bluez.InvalidArguments",
1636                                         "Invalid arguments in method call");
1637                 return;
1638         }
1639
1640         dbus_message_iter_get_basic(value, &chrc->handle);
1641
1642         print_chrc(chrc, COLORED_CHG);
1643
1644         g_dbus_pending_property_success(id);
1645 }
1646
1647 static gboolean chrc_get_uuid(const GDBusPropertyTable *property,
1648                                         DBusMessageIter *iter, void *data)
1649 {
1650         struct chrc *chrc = data;
1651
1652         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &chrc->uuid);
1653
1654         return TRUE;
1655 }
1656
1657 static gboolean chrc_get_service(const GDBusPropertyTable *property,
1658                                         DBusMessageIter *iter, void *data)
1659 {
1660         struct chrc *chrc = data;
1661
1662         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
1663                                                 &chrc->service->path);
1664
1665         return TRUE;
1666 }
1667
1668 static gboolean chrc_get_value(const GDBusPropertyTable *property,
1669                                         DBusMessageIter *iter, void *data)
1670 {
1671         struct chrc *chrc = data;
1672         DBusMessageIter array;
1673
1674         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
1675
1676         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
1677                                                 &chrc->value, chrc->value_len);
1678
1679         dbus_message_iter_close_container(iter, &array);
1680
1681         return TRUE;
1682 }
1683
1684 static gboolean chrc_get_notifying(const GDBusPropertyTable *property,
1685                                         DBusMessageIter *iter, void *data)
1686 {
1687         struct chrc *chrc = data;
1688         dbus_bool_t value;
1689
1690         value = chrc->notifying ? TRUE : FALSE;
1691
1692         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
1693
1694         return TRUE;
1695 }
1696
1697 static gboolean chrc_get_flags(const GDBusPropertyTable *property,
1698                                         DBusMessageIter *iter, void *data)
1699 {
1700         struct chrc *chrc = data;
1701         int i;
1702         DBusMessageIter array;
1703
1704         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
1705
1706         for (i = 0; chrc->flags[i]; i++)
1707                 dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
1708                                                         &chrc->flags[i]);
1709
1710         dbus_message_iter_close_container(iter, &array);
1711
1712         return TRUE;
1713 }
1714
1715 static gboolean chrc_get_write_acquired(const GDBusPropertyTable *property,
1716                                         DBusMessageIter *iter, void *data)
1717 {
1718         struct chrc *chrc = data;
1719         dbus_bool_t value;
1720
1721         value = chrc->write_io ? TRUE : FALSE;
1722
1723         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
1724
1725         return TRUE;
1726 }
1727
1728 static gboolean chrc_write_acquired_exists(const GDBusPropertyTable *property,
1729                                                                 void *data)
1730 {
1731         struct chrc *chrc = data;
1732         int i;
1733
1734         if (chrc->proxy)
1735                 return FALSE;
1736
1737         for (i = 0; chrc->flags[i]; i++) {
1738                 if (!strcmp("write-without-response", chrc->flags[i]))
1739                         return TRUE;
1740         }
1741
1742         return FALSE;
1743 }
1744
1745 static gboolean chrc_get_notify_acquired(const GDBusPropertyTable *property,
1746                                         DBusMessageIter *iter, void *data)
1747 {
1748         struct chrc *chrc = data;
1749         dbus_bool_t value;
1750
1751         value = chrc->notify_io ? TRUE : FALSE;
1752
1753         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
1754
1755         return TRUE;
1756 }
1757
1758 static gboolean chrc_notify_acquired_exists(const GDBusPropertyTable *property,
1759                                                                 void *data)
1760 {
1761         struct chrc *chrc = data;
1762         int i;
1763
1764         if (chrc->proxy)
1765                 return FALSE;
1766
1767         for (i = 0; chrc->flags[i]; i++) {
1768                 if (!strcmp("notify", chrc->flags[i]))
1769                         return TRUE;
1770         }
1771
1772         return FALSE;
1773 }
1774
1775 static const GDBusPropertyTable chrc_properties[] = {
1776         { "Handle", "q", chrc_get_handle, chrc_set_handle, NULL },
1777         { "UUID", "s", chrc_get_uuid, NULL, NULL },
1778         { "Service", "o", chrc_get_service, NULL, NULL },
1779         { "Value", "ay", chrc_get_value, NULL, NULL },
1780         { "Notifying", "b", chrc_get_notifying, NULL, NULL },
1781         { "Flags", "as", chrc_get_flags, NULL, NULL },
1782         { "WriteAcquired", "b", chrc_get_write_acquired, NULL,
1783                                         chrc_write_acquired_exists },
1784         { "NotifyAcquired", "b", chrc_get_notify_acquired, NULL,
1785                                         chrc_notify_acquired_exists },
1786         { }
1787 };
1788
1789 static const char *path_to_address(const char *path)
1790 {
1791         GDBusProxy *proxy;
1792         DBusMessageIter iter;
1793         const char *address = path;
1794
1795         proxy = bt_shell_get_env(path);
1796
1797         if (g_dbus_proxy_get_property(proxy, "Address", &iter))
1798                 dbus_message_iter_get_basic(&iter, &address);
1799
1800         return address;
1801 }
1802
1803 static int parse_options(DBusMessageIter *iter, uint16_t *offset, uint16_t *mtu,
1804                                                 char **device, char **link,
1805                                                 bool *prep_authorize)
1806 {
1807         DBusMessageIter dict;
1808
1809         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
1810                 return -EINVAL;
1811
1812         dbus_message_iter_recurse(iter, &dict);
1813
1814         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1815                 const char *key;
1816                 DBusMessageIter value, entry;
1817                 int var;
1818
1819                 dbus_message_iter_recurse(&dict, &entry);
1820                 dbus_message_iter_get_basic(&entry, &key);
1821
1822                 dbus_message_iter_next(&entry);
1823                 dbus_message_iter_recurse(&entry, &value);
1824
1825                 var = dbus_message_iter_get_arg_type(&value);
1826                 if (strcasecmp(key, "offset") == 0) {
1827                         if (var != DBUS_TYPE_UINT16)
1828                                 return -EINVAL;
1829                         if (offset)
1830                                 dbus_message_iter_get_basic(&value, offset);
1831                 } else if (strcasecmp(key, "MTU") == 0) {
1832                         if (var != DBUS_TYPE_UINT16)
1833                                 return -EINVAL;
1834                         if (mtu)
1835                                 dbus_message_iter_get_basic(&value, mtu);
1836                 } else if (strcasecmp(key, "device") == 0) {
1837                         if (var != DBUS_TYPE_OBJECT_PATH)
1838                                 return -EINVAL;
1839                         if (device)
1840                                 dbus_message_iter_get_basic(&value, device);
1841                 } else if (strcasecmp(key, "link") == 0) {
1842                         if (var != DBUS_TYPE_STRING)
1843                                 return -EINVAL;
1844                         if (link)
1845                                 dbus_message_iter_get_basic(&value, link);
1846                 } else if (strcasecmp(key, "prepare-authorize") == 0) {
1847                         if (var != DBUS_TYPE_BOOLEAN)
1848                                 return -EINVAL;
1849                         if (prep_authorize) {
1850                                 int tmp;
1851
1852                                 dbus_message_iter_get_basic(&value, &tmp);
1853                                 *prep_authorize = !!tmp;
1854                         }
1855                 }
1856
1857                 dbus_message_iter_next(&dict);
1858         }
1859
1860         return 0;
1861 }
1862
1863 static DBusMessage *read_value(DBusMessage *msg, uint8_t *value,
1864                                                 uint16_t value_len)
1865 {
1866         DBusMessage *reply;
1867         DBusMessageIter iter, array;
1868
1869         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
1870
1871         dbus_message_iter_init_append(reply, &iter);
1872         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "y", &array);
1873         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
1874                                                 &value, value_len);
1875         dbus_message_iter_close_container(&iter, &array);
1876
1877         return reply;
1878 }
1879
1880 struct authorize_attribute_data {
1881         DBusConnection *conn;
1882         void *attribute;
1883         uint16_t offset;
1884 };
1885
1886 static void authorize_read_response(const char *input, void *user_data)
1887 {
1888         struct authorize_attribute_data *aad = user_data;
1889         struct chrc *chrc = aad->attribute;
1890         DBusMessage *reply;
1891         char *err;
1892
1893         if (!strcmp(input, "no")) {
1894                 err = "org.bluez.Error.NotAuthorized";
1895
1896                 goto error;
1897         }
1898
1899         if (aad->offset > chrc->value_len) {
1900                 err = "org.bluez.Error.InvalidOffset";
1901
1902                 goto error;
1903         }
1904
1905         reply = read_value(pending_message, &chrc->value[aad->offset],
1906                                                 chrc->value_len - aad->offset);
1907
1908         g_dbus_send_message(aad->conn, reply);
1909
1910         g_free(aad);
1911
1912         return;
1913
1914 error:
1915         g_dbus_send_error(aad->conn, pending_message, err, NULL);
1916         g_free(aad);
1917 }
1918
1919 static bool is_device_trusted(const char *path)
1920 {
1921         GDBusProxy *proxy;
1922         DBusMessageIter iter;
1923         bool trusted = false;
1924
1925         proxy = bt_shell_get_env(path);
1926
1927         if (g_dbus_proxy_get_property(proxy, "Trusted", &iter))
1928                 dbus_message_iter_get_basic(&iter, &trusted);
1929
1930         return trusted;
1931 }
1932
1933 struct read_attribute_data {
1934         DBusMessage *msg;
1935         uint16_t offset;
1936 };
1937
1938 static void proxy_read_reply(DBusMessage *message, void *user_data)
1939 {
1940         struct read_attribute_data *data = user_data;
1941         DBusConnection *conn = bt_shell_get_env("DBUS_CONNECTION");
1942         DBusError error;
1943         DBusMessageIter iter, array;
1944         DBusMessage *reply;
1945         uint8_t *value;
1946         int len;
1947
1948         dbus_error_init(&error);
1949
1950         if (dbus_set_error_from_message(&error, message) == TRUE) {
1951                 bt_shell_printf("Failed to read: %s\n", error.name);
1952                 dbus_error_free(&error);
1953                 g_dbus_send_error(conn, data->msg, error.name, "%s",
1954                                                         error.message);
1955                 goto done;
1956         }
1957
1958         dbus_message_iter_init(message, &iter);
1959
1960         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
1961                 bt_shell_printf("Invalid response to read\n");
1962                 g_dbus_send_error(conn, data->msg,
1963                                 "org.bluez.Error.InvalidArguments", NULL);
1964                 goto done;
1965         }
1966
1967         dbus_message_iter_recurse(&iter, &array);
1968         dbus_message_iter_get_fixed_array(&array, &value, &len);
1969
1970         if (len < 0) {
1971                 bt_shell_printf("Unable to parse value\n");
1972                 g_dbus_send_error(conn, data->msg,
1973                                 "org.bluez.Error.InvalidArguments", NULL);
1974         }
1975
1976         reply = read_value(data->msg, value, len);
1977
1978         g_dbus_send_message(conn, reply);
1979
1980 done:
1981         dbus_message_unref(data->msg);
1982         free(data);
1983 }
1984
1985 static void proxy_read_setup(DBusMessageIter *iter, void *user_data)
1986 {
1987         DBusMessageIter dict;
1988         struct read_attribute_data *data = user_data;
1989
1990         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1991                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1992                                         DBUS_TYPE_STRING_AS_STRING
1993                                         DBUS_TYPE_VARIANT_AS_STRING
1994                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1995                                         &dict);
1996
1997         g_dbus_dict_append_entry(&dict, "offset", DBUS_TYPE_UINT16,
1998                                                 &data->offset);
1999
2000         dbus_message_iter_close_container(iter, &dict);
2001 }
2002
2003 static DBusMessage *proxy_read_value(struct GDBusProxy *proxy, DBusMessage *msg,
2004                                                         uint16_t offset)
2005 {
2006         struct read_attribute_data *data;
2007
2008         data = new0(struct read_attribute_data, 1);
2009         data->msg = dbus_message_ref(msg);
2010         data->offset = offset;
2011
2012         if (g_dbus_proxy_method_call(proxy, "ReadValue", proxy_read_setup,
2013                                         proxy_read_reply, data, NULL))
2014                 return NULL;
2015
2016         bt_shell_printf("Failed to read\n");
2017
2018         return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
2019                                                                 NULL);
2020 }
2021
2022 static DBusMessage *chrc_read_value(DBusConnection *conn, DBusMessage *msg,
2023                                                         void *user_data)
2024 {
2025         struct chrc *chrc = user_data;
2026         DBusMessageIter iter;
2027         uint16_t offset = 0;
2028         char *device, *link;
2029         char *str;
2030
2031         dbus_message_iter_init(msg, &iter);
2032
2033         if (parse_options(&iter, &offset, NULL, &device, &link, NULL))
2034                 return g_dbus_create_error(msg,
2035                                         "org.bluez.Error.InvalidArguments",
2036                                         NULL);
2037
2038         bt_shell_printf("[%s (%s)] ReadValue: %s offset %u link %s\n",
2039                         chrc->path, bt_uuidstr_to_str(chrc->uuid),
2040                         path_to_address(device), offset, link);
2041
2042         if (chrc->proxy) {
2043                 return proxy_read_value(chrc->proxy, msg, offset);
2044         }
2045
2046         if (!is_device_trusted(device) && chrc->authorization_req) {
2047                 struct authorize_attribute_data *aad;
2048
2049                 aad = g_new0(struct authorize_attribute_data, 1);
2050                 aad->conn = conn;
2051                 aad->attribute = chrc;
2052                 aad->offset = offset;
2053
2054                 str = g_strdup_printf("Authorize attribute(%s) read (yes/no):",
2055                                                                 chrc->path);
2056
2057                 bt_shell_prompt_input("gatt", str, authorize_read_response,
2058                                                                         aad);
2059                 g_free(str);
2060
2061                 pending_message = dbus_message_ref(msg);
2062
2063                 return NULL;
2064         }
2065
2066         if (offset > chrc->value_len)
2067                 return g_dbus_create_error(msg, "org.bluez.Error.InvalidOffset",
2068                                                                         NULL);
2069
2070         return read_value(msg, &chrc->value[offset], chrc->value_len - offset);
2071 }
2072
2073 static int parse_value_arg(DBusMessageIter *iter, uint8_t **value, int *len)
2074 {
2075         DBusMessageIter array;
2076
2077         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
2078                 return -EINVAL;
2079
2080         dbus_message_iter_recurse(iter, &array);
2081         dbus_message_iter_get_fixed_array(&array, value, len);
2082
2083         return 0;
2084 }
2085
2086 static int write_value(size_t *dst_len, uint8_t **dst_value, uint8_t *src_val,
2087                         size_t src_len, uint16_t offset, uint16_t max_len)
2088 {
2089         if ((offset + src_len) > max_len)
2090                 return -EOVERFLOW;
2091
2092         if ((offset + src_len) != *dst_len) {
2093                 *dst_len = offset + src_len;
2094                 *dst_value = g_realloc(*dst_value, *dst_len);
2095         }
2096
2097         memcpy(*dst_value + offset, src_val, src_len);
2098
2099         return 0;
2100 }
2101
2102 static void authorize_write_response(const char *input, void *user_data)
2103 {
2104         struct authorize_attribute_data *aad = user_data;
2105         struct chrc *chrc = aad->attribute;
2106         bool prep_authorize = false;
2107         DBusMessageIter iter;
2108         DBusMessage *reply;
2109         int value_len;
2110         uint8_t *value;
2111         char *err;
2112
2113         dbus_message_iter_init(pending_message, &iter);
2114         if (parse_value_arg(&iter, &value, &value_len)) {
2115                 err = "org.bluez.Error.InvalidArguments";
2116
2117                 goto error;
2118         }
2119
2120         dbus_message_iter_next(&iter);
2121         if (parse_options(&iter, NULL, NULL, NULL, NULL, &prep_authorize)) {
2122                 err = "org.bluez.Error.InvalidArguments";
2123
2124                 goto error;
2125         }
2126
2127         if (!strcmp(input, "no")) {
2128                 err = "org.bluez.Error.NotAuthorized";
2129
2130                 goto error;
2131         }
2132
2133         if (aad->offset > chrc->value_len) {
2134                 err = "org.bluez.Error.InvalidOffset";
2135
2136                 goto error;
2137         }
2138
2139         /* Authorization check of prepare writes */
2140         if (prep_authorize) {
2141                 reply = g_dbus_create_reply(pending_message, DBUS_TYPE_INVALID);
2142                 g_dbus_send_message(aad->conn, reply);
2143                 g_free(aad);
2144
2145                 return;
2146         }
2147
2148         if (write_value(&chrc->value_len, &chrc->value, value, value_len,
2149                                         aad->offset, chrc->max_val_len)) {
2150                 err = "org.bluez.Error.InvalidValueLength";
2151
2152                 goto error;
2153         }
2154
2155         bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) written",
2156                         chrc->path, bt_uuidstr_to_str(chrc->uuid));
2157
2158         g_dbus_emit_property_changed(aad->conn, chrc->path, CHRC_INTERFACE,
2159                                                                 "Value");
2160
2161         reply = g_dbus_create_reply(pending_message, DBUS_TYPE_INVALID);
2162         g_dbus_send_message(aad->conn, reply);
2163
2164         g_free(aad);
2165
2166         return;
2167
2168 error:
2169         g_dbus_send_error(aad->conn, pending_message, err, NULL);
2170         g_free(aad);
2171 }
2172
2173 static void proxy_write_reply(DBusMessage *message, void *user_data)
2174 {
2175         struct write_attribute_data *data = user_data;
2176         DBusConnection *conn = bt_shell_get_env("DBUS_CONNECTION");
2177         DBusError error;
2178
2179         dbus_error_init(&error);
2180
2181         if (dbus_set_error_from_message(&error, message)) {
2182                 bt_shell_printf("Failed to write: %s\n", error.name);
2183                 g_dbus_send_error(conn, data->msg, error.name, "%s",
2184                                                         error.message);
2185         } else
2186                 g_dbus_send_reply(conn, data->msg, DBUS_TYPE_INVALID);
2187
2188         dbus_message_unref(data->msg);
2189         free(data);
2190 }
2191
2192 static DBusMessage *proxy_write_value(struct GDBusProxy *proxy,
2193                                         DBusMessage *msg, uint8_t *value,
2194                                         int value_len, uint16_t offset)
2195 {
2196         struct write_attribute_data *data;
2197
2198
2199         data = new0(struct write_attribute_data, 1);
2200         data->msg = dbus_message_ref(msg);
2201         data->iov.iov_base = (void *) value;
2202         data->iov.iov_len = value_len;
2203         data->offset = offset;
2204
2205         if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup,
2206                                         proxy_write_reply, data, NULL))
2207                 return NULL;
2208
2209
2210         bt_shell_printf("Failed to write\n");
2211
2212         return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
2213                                                                 NULL);
2214 }
2215
2216 static DBusMessage *chrc_write_value(DBusConnection *conn, DBusMessage *msg,
2217                                                         void *user_data)
2218 {
2219         struct chrc *chrc = user_data;
2220         uint16_t offset = 0;
2221         bool prep_authorize = false;
2222         char *device = NULL, *link = NULL;
2223         DBusMessageIter iter;
2224         int value_len;
2225         uint8_t *value;
2226         char *str;
2227
2228         dbus_message_iter_init(msg, &iter);
2229
2230         if (parse_value_arg(&iter, &value, &value_len))
2231                 return g_dbus_create_error(msg,
2232                                 "org.bluez.Error.InvalidArguments", NULL);
2233
2234         dbus_message_iter_next(&iter);
2235         if (parse_options(&iter, &offset, NULL, &device, &link,
2236                                                 &prep_authorize))
2237                 return g_dbus_create_error(msg,
2238                                 "org.bluez.Error.InvalidArguments", NULL);
2239
2240         bt_shell_printf("[%s (%s)] WriteValue: %s offset %u link %s\n",
2241                         chrc->path, bt_uuidstr_to_str(chrc->uuid),
2242                         path_to_address(device), offset, link);
2243
2244         bt_shell_hexdump(value, value_len);
2245
2246         if (chrc->proxy)
2247                 return proxy_write_value(chrc->proxy, msg, value, value_len,
2248                                                                 offset);
2249
2250         if (!is_device_trusted(device) && chrc->authorization_req) {
2251                 struct authorize_attribute_data *aad;
2252
2253                 aad = g_new0(struct authorize_attribute_data, 1);
2254                 aad->conn = conn;
2255                 aad->attribute = chrc;
2256                 aad->offset = offset;
2257
2258                 str = g_strdup_printf("Authorize attribute(%s) write (yes/no):",
2259                                                                 chrc->path);
2260
2261                 bt_shell_prompt_input("gatt", str, authorize_write_response,
2262                                                                         aad);
2263                 g_free(str);
2264
2265                 pending_message = dbus_message_ref(msg);
2266
2267                 return NULL;
2268         }
2269
2270         if (offset > chrc->value_len)
2271                 return g_dbus_create_error(msg,
2272                                 "org.bluez.Error.InvalidOffset", NULL);
2273
2274
2275         /* Authorization check of prepare writes */
2276         if (prep_authorize)
2277                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2278
2279         if (write_value(&chrc->value_len, &chrc->value, value, value_len,
2280                                                 offset, chrc->max_val_len))
2281                 return g_dbus_create_error(msg,
2282                                 "org.bluez.Error.InvalidValueLength", NULL);
2283
2284         bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) written",
2285                         chrc->path, bt_uuidstr_to_str(chrc->uuid));
2286
2287         g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE, "Value");
2288
2289         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2290 }
2291
2292 static DBusMessage *create_sock(struct chrc *chrc, DBusMessage *msg)
2293 {
2294         int fds[2];
2295         struct io *io;
2296         bool dir;
2297         DBusMessage *reply;
2298
2299         if (socketpair(AF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC,
2300                                                                 0, fds) < 0)
2301                 return g_dbus_create_error(msg, "org.bluez.Error.Failed", "%s",
2302                                                         strerror(errno));
2303
2304         dir = dbus_message_has_member(msg, "AcquireWrite");
2305
2306         io = sock_io_new(fds[!dir], chrc);
2307         if (!io) {
2308                 close(fds[0]);
2309                 close(fds[1]);
2310                 return g_dbus_create_error(msg, "org.bluez.Error.Failed", "%s",
2311                                                         strerror(errno));
2312         }
2313
2314         reply = g_dbus_create_reply(msg, DBUS_TYPE_UNIX_FD, &fds[dir],
2315                                         DBUS_TYPE_UINT16, &chrc->mtu,
2316                                         DBUS_TYPE_INVALID);
2317
2318         close(fds[dir]);
2319
2320         if (dir)
2321                 chrc->write_io = io;
2322         else
2323                 chrc->notify_io = io;
2324
2325         bt_shell_printf("[" COLORED_CHG "] Attribute %s %s sock acquired\n",
2326                                         chrc->path, dir ? "Write" : "Notify");
2327
2328         return reply;
2329 }
2330
2331 static DBusMessage *chrc_acquire_write(DBusConnection *conn, DBusMessage *msg,
2332                                                         void *user_data)
2333 {
2334         struct chrc *chrc = user_data;
2335         DBusMessageIter iter;
2336         DBusMessage *reply;
2337         char *device = NULL, *link= NULL;
2338
2339         dbus_message_iter_init(msg, &iter);
2340
2341         if (chrc->write_io)
2342                 return g_dbus_create_error(msg,
2343                                         "org.bluez.Error.NotPermitted",
2344                                         NULL);
2345
2346         if (parse_options(&iter, NULL, &chrc->mtu, &device, &link, NULL))
2347                 return g_dbus_create_error(msg,
2348                                         "org.bluez.Error.InvalidArguments",
2349                                         NULL);
2350
2351         bt_shell_printf("AcquireWrite: %s link %s\n", path_to_address(device),
2352                                                                         link);
2353
2354         reply = create_sock(chrc, msg);
2355
2356         if (chrc->write_io)
2357                 g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
2358                                                         "WriteAcquired");
2359
2360         return reply;
2361 }
2362
2363 static DBusMessage *chrc_acquire_notify(DBusConnection *conn, DBusMessage *msg,
2364                                                         void *user_data)
2365 {
2366         struct chrc *chrc = user_data;
2367         DBusMessageIter iter;
2368         DBusMessage *reply;
2369         char *device = NULL, *link = NULL;
2370
2371         dbus_message_iter_init(msg, &iter);
2372
2373         if (chrc->notify_io)
2374                 return g_dbus_create_error(msg,
2375                                         "org.bluez.Error.NotPermitted",
2376                                         NULL);
2377
2378         if (parse_options(&iter, NULL, &chrc->mtu, &device, &link, NULL))
2379                 return g_dbus_create_error(msg,
2380                                         "org.bluez.Error.InvalidArguments",
2381                                         NULL);
2382
2383         bt_shell_printf("AcquireNotify: %s link %s\n", path_to_address(device),
2384                                                                         link);
2385
2386         reply = create_sock(chrc, msg);
2387
2388         if (chrc->notify_io)
2389                 g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
2390                                                         "NotifyAcquired");
2391
2392         return reply;
2393 }
2394
2395 struct notify_attribute_data {
2396         struct chrc *chrc;
2397         DBusMessage *msg;
2398         bool enable;
2399 };
2400
2401 static void proxy_notify_reply(DBusMessage *message, void *user_data)
2402 {
2403         struct notify_attribute_data *data = user_data;
2404         DBusConnection *conn = bt_shell_get_env("DBUS_CONNECTION");
2405         DBusError error;
2406
2407         dbus_error_init(&error);
2408
2409         if (dbus_set_error_from_message(&error, message) == TRUE) {
2410                 bt_shell_printf("Failed to %s: %s\n",
2411                                 data->enable ? "StartNotify" : "StopNotify",
2412                                 error.name);
2413                 dbus_error_free(&error);
2414                 g_dbus_send_error(conn, data->msg, error.name, "%s",
2415                                                         error.message);
2416                 goto done;
2417         }
2418
2419         g_dbus_send_reply(conn, data->msg, DBUS_TYPE_INVALID);
2420
2421         data->chrc->notifying = data->enable;
2422         bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) "
2423                                 "notifications %s\n",
2424                                 data->chrc->path,
2425                                 bt_uuidstr_to_str(data->chrc->uuid),
2426                                 data->enable ? "enabled" : "disabled");
2427         g_dbus_emit_property_changed(conn, data->chrc->path, CHRC_INTERFACE,
2428                                                         "Notifying");
2429
2430 done:
2431         dbus_message_unref(data->msg);
2432         free(data);
2433 }
2434
2435 static DBusMessage *proxy_notify(struct chrc *chrc, DBusMessage *msg,
2436                                                         bool enable)
2437 {
2438         struct notify_attribute_data *data;
2439         const char *method;
2440
2441         if (enable == TRUE)
2442                 method = "StartNotify";
2443         else
2444                 method = "StopNotify";
2445
2446         data = new0(struct notify_attribute_data, 1);
2447         data->chrc = chrc;
2448         data->msg = dbus_message_ref(msg);
2449         data->enable = enable;
2450
2451         if (g_dbus_proxy_method_call(chrc->proxy, method, NULL,
2452                                         proxy_notify_reply, data, NULL))
2453                 return NULL;
2454
2455         return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
2456                                                                 NULL);
2457 }
2458
2459 static DBusMessage *chrc_start_notify(DBusConnection *conn, DBusMessage *msg,
2460                                                         void *user_data)
2461 {
2462         struct chrc *chrc = user_data;
2463
2464         if (chrc->notifying)
2465                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2466
2467         if (chrc->proxy)
2468                 return proxy_notify(chrc, msg, true);
2469
2470         chrc->notifying = true;
2471         bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) notifications "
2472                         "enabled", chrc->path, bt_uuidstr_to_str(chrc->uuid));
2473         g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
2474                                                         "Notifying");
2475
2476         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2477 }
2478
2479 static DBusMessage *chrc_stop_notify(DBusConnection *conn, DBusMessage *msg,
2480                                                         void *user_data)
2481 {
2482         struct chrc *chrc = user_data;
2483
2484         if (!chrc->notifying)
2485                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2486
2487         if (chrc->proxy)
2488                 return proxy_notify(chrc, msg, false);
2489
2490         chrc->notifying = false;
2491         bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) notifications "
2492                         "disabled", chrc->path, bt_uuidstr_to_str(chrc->uuid));
2493         g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE,
2494                                                         "Notifying");
2495
2496         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2497 }
2498
2499 static DBusMessage *chrc_confirm(DBusConnection *conn, DBusMessage *msg,
2500                                                         void *user_data)
2501 {
2502         struct chrc *chrc = user_data;
2503
2504         bt_shell_printf("Attribute %s (%s) indication confirm received",
2505                         chrc->path, bt_uuidstr_to_str(chrc->uuid));
2506
2507         return dbus_message_new_method_return(msg);
2508 }
2509
2510 static const GDBusMethodTable chrc_methods[] = {
2511         { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
2512                                         GDBUS_ARGS({ "value", "ay" }),
2513                                         chrc_read_value) },
2514         { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
2515                                                 { "options", "a{sv}" }),
2516                                         NULL, chrc_write_value) },
2517         { GDBUS_METHOD("AcquireWrite", GDBUS_ARGS({ "options", "a{sv}" }),
2518                                         NULL, chrc_acquire_write) },
2519         { GDBUS_METHOD("AcquireNotify", GDBUS_ARGS({ "options", "a{sv}" }),
2520                                         NULL, chrc_acquire_notify) },
2521         { GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL, chrc_start_notify) },
2522         { GDBUS_METHOD("StopNotify", NULL, NULL, chrc_stop_notify) },
2523         { GDBUS_METHOD("Confirm", NULL, NULL, chrc_confirm) },
2524         { }
2525 };
2526
2527 static void chrc_set_value(const char *input, void *user_data)
2528 {
2529         struct chrc *chrc = user_data;
2530
2531         g_free(chrc->value);
2532
2533         chrc->value = str2bytearray((char *) input, &chrc->value_len);
2534
2535         if (!chrc->value) {
2536                 print_chrc(chrc, COLORED_DEL);
2537                 chrc_unregister(chrc);
2538         }
2539
2540         chrc->max_val_len = chrc->value_len;
2541 }
2542
2543 static gboolean attr_authorization_flag_exists(char **flags)
2544 {
2545         int i;
2546
2547         for (i = 0; flags[i]; i++) {
2548                 if (!strcmp("authorize", flags[i]))
2549                         return TRUE;
2550         }
2551
2552         return FALSE;
2553 }
2554
2555 void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy,
2556                                         int argc, char *argv[])
2557 {
2558         struct service *service;
2559         struct chrc *chrc;
2560
2561         if (!local_services) {
2562                 bt_shell_printf("No service registered\n");
2563                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2564         }
2565
2566         service = g_list_last(local_services)->data;
2567
2568         chrc = g_new0(struct chrc, 1);
2569         chrc->service = service;
2570         chrc->uuid = g_strdup(argv[1]);
2571         chrc->path = g_strdup_printf("%s/chrc%u", service->path,
2572                                         g_list_length(service->chrcs));
2573         chrc->flags = g_strsplit(argv[2], ",", -1);
2574         chrc->authorization_req = attr_authorization_flag_exists(chrc->flags);
2575
2576         if (argc > 3)
2577                 chrc->handle = atoi(argv[3]);
2578
2579         if (g_dbus_register_interface(conn, chrc->path, CHRC_INTERFACE,
2580                                         chrc_methods, NULL, chrc_properties,
2581                                         chrc, chrc_free) == FALSE) {
2582                 bt_shell_printf("Failed to register characteristic object\n");
2583                 chrc_free(chrc);
2584                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2585         }
2586
2587         service->chrcs = g_list_append(service->chrcs, chrc);
2588
2589         print_chrc(chrc, COLORED_NEW);
2590
2591         bt_shell_prompt_input(chrc->path, "Enter value:", chrc_set_value, chrc);
2592
2593         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
2594 }
2595
2596 static struct chrc *chrc_find(const char *pattern)
2597 {
2598         GList *l, *lc;
2599         struct service *service;
2600         struct chrc *chrc;
2601
2602         for (l = local_services; l; l = g_list_next(l)) {
2603                 service = l->data;
2604
2605                 for (lc = service->chrcs; lc; lc =  g_list_next(lc)) {
2606                         chrc = lc->data;
2607
2608                         /* match object path */
2609                         if (!strcmp(chrc->path, pattern))
2610                                 return chrc;
2611
2612                         /* match UUID */
2613                         if (!strcmp(chrc->uuid, pattern))
2614                                 return chrc;
2615                 }
2616         }
2617
2618         return NULL;
2619 }
2620
2621 void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
2622                                                 int argc, char *argv[])
2623 {
2624         struct chrc *chrc;
2625
2626         chrc = chrc_find(argv[1]);
2627         if (!chrc) {
2628                 bt_shell_printf("Failed to unregister characteristic object\n");
2629                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2630         }
2631
2632         chrc->service->chrcs = g_list_remove(chrc->service->chrcs, chrc);
2633
2634         chrc_unregister(chrc);
2635
2636         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
2637 }
2638
2639 static DBusMessage *desc_read_value(DBusConnection *conn, DBusMessage *msg,
2640                                                         void *user_data)
2641 {
2642         struct desc *desc = user_data;
2643         DBusMessageIter iter;
2644         uint16_t offset = 0;
2645         char *device = NULL, *link = NULL;
2646
2647         dbus_message_iter_init(msg, &iter);
2648
2649         if (parse_options(&iter, &offset, NULL, &device, &link, NULL))
2650                 return g_dbus_create_error(msg,
2651                                         "org.bluez.Error.InvalidArguments",
2652                                         NULL);
2653
2654         bt_shell_printf("[%s (%s)] ReadValue: %s offset %u link %s\n",
2655                         desc->path, bt_uuidstr_to_str(desc->uuid),
2656                         path_to_address(device), offset, link);
2657
2658         if (offset > desc->value_len)
2659                 return g_dbus_create_error(msg, "org.bluez.Error.InvalidOffset",
2660                                                                         NULL);
2661
2662         return read_value(msg, &desc->value[offset], desc->value_len - offset);
2663 }
2664
2665 static DBusMessage *desc_write_value(DBusConnection *conn, DBusMessage *msg,
2666                                                         void *user_data)
2667 {
2668         struct desc *desc = user_data;
2669         DBusMessageIter iter;
2670         uint16_t offset = 0;
2671         char *device = NULL, *link = NULL;
2672         int value_len;
2673         uint8_t *value;
2674
2675         dbus_message_iter_init(msg, &iter);
2676
2677         if (parse_value_arg(&iter, &value, &value_len))
2678                 return g_dbus_create_error(msg,
2679                                 "org.bluez.Error.InvalidArguments", NULL);
2680
2681         dbus_message_iter_next(&iter);
2682         if (parse_options(&iter, &offset, NULL, &device, &link, NULL))
2683                 return g_dbus_create_error(msg,
2684                                 "org.bluez.Error.InvalidArguments", NULL);
2685
2686         if (offset > desc->value_len)
2687                 return g_dbus_create_error(msg,
2688                                 "org.bluez.Error.InvalidOffset", NULL);
2689
2690         if (write_value(&desc->value_len, &desc->value, value,
2691                                         value_len, offset, desc->max_val_len))
2692                 return g_dbus_create_error(msg,
2693                                 "org.bluez.Error.InvalidValueLength", NULL);
2694
2695         bt_shell_printf("[%s (%s)] WriteValue: %s offset %u link %s\n",
2696                         desc->path, bt_uuidstr_to_str(desc->uuid),
2697                         path_to_address(device), offset, link);
2698
2699         bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) written",
2700                         desc->path, bt_uuidstr_to_str(desc->uuid));
2701
2702         g_dbus_emit_property_changed(conn, desc->path, CHRC_INTERFACE, "Value");
2703
2704         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2705 }
2706
2707 static const GDBusMethodTable desc_methods[] = {
2708         { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
2709                                         GDBUS_ARGS({ "value", "ay" }),
2710                                         desc_read_value) },
2711         { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
2712                                                 { "options", "a{sv}" }),
2713                                         NULL, desc_write_value) },
2714         { }
2715 };
2716
2717 static gboolean desc_get_handle(const GDBusPropertyTable *property,
2718                                         DBusMessageIter *iter, void *data)
2719 {
2720         struct desc *desc = data;
2721
2722         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &desc->handle);
2723
2724         return TRUE;
2725 }
2726
2727 static void desc_set_handle(const GDBusPropertyTable *property,
2728                         DBusMessageIter *value, GDBusPendingPropertySet id,
2729                         void *data)
2730 {
2731         struct desc *desc = data;
2732
2733         if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16) {
2734                 g_dbus_pending_property_error(id, "org.bluez.InvalidArguments",
2735                                         "Invalid arguments in method call");
2736                 return;
2737         }
2738
2739         dbus_message_iter_get_basic(value, &desc->handle);
2740
2741         print_desc(desc, COLORED_CHG);
2742
2743         g_dbus_pending_property_success(id);
2744 }
2745
2746 static gboolean desc_get_uuid(const GDBusPropertyTable *property,
2747                                         DBusMessageIter *iter, void *data)
2748 {
2749         struct desc *desc = data;
2750
2751         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &desc->uuid);
2752
2753         return TRUE;
2754 }
2755
2756 static gboolean desc_get_chrc(const GDBusPropertyTable *property,
2757                                         DBusMessageIter *iter, void *data)
2758 {
2759         struct desc *desc = data;
2760
2761         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2762                                                 &desc->chrc->path);
2763
2764         return TRUE;
2765 }
2766
2767 static gboolean desc_get_value(const GDBusPropertyTable *property,
2768                                         DBusMessageIter *iter, void *data)
2769 {
2770         struct desc *desc = data;
2771         DBusMessageIter array;
2772
2773         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
2774
2775         if (desc->value)
2776                 dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
2777                                                         &desc->value,
2778                                                         desc->value_len);
2779
2780         dbus_message_iter_close_container(iter, &array);
2781
2782         return TRUE;
2783 }
2784
2785 static gboolean desc_get_flags(const GDBusPropertyTable *property,
2786                                         DBusMessageIter *iter, void *data)
2787 {
2788         struct desc *desc = data;
2789         int i;
2790         DBusMessageIter array;
2791
2792         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
2793
2794         for (i = 0; desc->flags[i]; i++)
2795                 dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
2796                                                         &desc->flags[i]);
2797
2798         dbus_message_iter_close_container(iter, &array);
2799
2800         return TRUE;
2801 }
2802
2803 static const GDBusPropertyTable desc_properties[] = {
2804         { "Handle", "q", desc_get_handle, desc_set_handle, NULL },
2805         { "UUID", "s", desc_get_uuid, NULL, NULL },
2806         { "Characteristic", "o", desc_get_chrc, NULL, NULL },
2807         { "Value", "ay", desc_get_value, NULL, NULL },
2808         { "Flags", "as", desc_get_flags, NULL, NULL },
2809         { }
2810 };
2811
2812 static void desc_set_value(const char *input, void *user_data)
2813 {
2814         struct desc *desc = user_data;
2815
2816         g_free(desc->value);
2817
2818         desc->value = str2bytearray((char *) input, &desc->value_len);
2819
2820         if (!desc->value) {
2821                 print_desc(desc, COLORED_DEL);
2822                 desc_unregister(desc);
2823         }
2824
2825         desc->max_val_len = desc->value_len;
2826 }
2827
2828 void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy,
2829                                                 int argc, char *argv[])
2830 {
2831         struct service *service;
2832         struct desc *desc;
2833
2834         if (!local_services) {
2835                 bt_shell_printf("No service registered\n");
2836                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2837         }
2838
2839         service = g_list_last(local_services)->data;
2840
2841         if (!service->chrcs) {
2842                 bt_shell_printf("No characteristic registered\n");
2843                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2844         }
2845
2846         desc = g_new0(struct desc, 1);
2847         desc->chrc = g_list_last(service->chrcs)->data;
2848         desc->uuid = g_strdup(argv[1]);
2849         desc->path = g_strdup_printf("%s/desc%u", desc->chrc->path,
2850                                         g_list_length(desc->chrc->descs));
2851         desc->flags = g_strsplit(argv[2], ",", -1);
2852
2853         if (argc > 3)
2854                 desc->handle = atoi(argv[3]);
2855
2856         if (g_dbus_register_interface(conn, desc->path, DESC_INTERFACE,
2857                                         desc_methods, NULL, desc_properties,
2858                                         desc, desc_free) == FALSE) {
2859                 bt_shell_printf("Failed to register descriptor object\n");
2860                 desc_free(desc);
2861                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2862         }
2863
2864         desc->chrc->descs = g_list_append(desc->chrc->descs, desc);
2865
2866         print_desc(desc, COLORED_NEW);
2867
2868         bt_shell_prompt_input(desc->path, "Enter value:", desc_set_value, desc);
2869
2870         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
2871 }
2872
2873 static struct desc *desc_find(const char *pattern)
2874 {
2875         GList *l, *lc, *ld;
2876         struct service *service;
2877         struct chrc *chrc;
2878         struct desc *desc;
2879
2880         for (l = local_services; l; l = g_list_next(l)) {
2881                 service = l->data;
2882
2883                 for (lc = service->chrcs; lc; lc = g_list_next(lc)) {
2884                         chrc = lc->data;
2885
2886                         for (ld = chrc->descs; ld; ld = g_list_next(ld)) {
2887                                 desc = ld->data;
2888
2889                                 /* match object path */
2890                                 if (!strcmp(desc->path, pattern))
2891                                         return desc;
2892
2893                                 /* match UUID */
2894                                 if (!strcmp(desc->uuid, pattern))
2895                                         return desc;
2896                         }
2897                 }
2898         }
2899
2900         return NULL;
2901 }
2902
2903 void gatt_unregister_desc(DBusConnection *conn, GDBusProxy *proxy,
2904                                                 int argc, char *argv[])
2905 {
2906         struct desc *desc;
2907
2908         desc = desc_find(argv[1]);
2909         if (!desc) {
2910                 bt_shell_printf("Failed to unregister descriptor object\n");
2911                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
2912         }
2913
2914         desc->chrc->descs = g_list_remove(desc->chrc->descs, desc);
2915
2916         desc_unregister(desc);
2917
2918         return bt_shell_noninteractive_quit(EXIT_SUCCESS);
2919 }
2920
2921 static GDBusProxy *select_service(GDBusProxy *proxy)
2922 {
2923         GList *l;
2924
2925         for (l = services; l; l = g_list_next(l)) {
2926                 GDBusProxy *p = l->data;
2927
2928                 if (proxy == p || g_str_has_prefix(g_dbus_proxy_get_path(proxy),
2929                                                 g_dbus_proxy_get_path(p)))
2930                         return p;
2931         }
2932
2933         return NULL;
2934 }
2935
2936 static void proxy_property_changed(GDBusProxy *proxy, const char *name,
2937                                         DBusMessageIter *iter, void *user_data)
2938 {
2939         DBusConnection *conn = bt_shell_get_env("DBUS_CONNECTION");
2940         struct chrc *chrc = user_data;
2941
2942         bt_shell_printf("[" COLORED_CHG "] Attribute %s (%s) %s:\n",
2943                         chrc->path, bt_uuidstr_to_str(chrc->uuid), name);
2944
2945         if (!strcmp(name, "Value")) {
2946                 DBusMessageIter array;
2947                 uint8_t *value;
2948                 int len;
2949
2950                 if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
2951                         dbus_message_iter_recurse(iter, &array);
2952                         dbus_message_iter_get_fixed_array(&array, &value, &len);
2953                         write_value(&chrc->value_len, &chrc->value, value, len,
2954                                         0, chrc->max_val_len);
2955                         bt_shell_hexdump(value, len);
2956                 }
2957         }
2958
2959         g_dbus_emit_property_changed(conn, chrc->path, CHRC_INTERFACE, name);
2960 }
2961
2962 static void clone_chrc(struct GDBusProxy *proxy)
2963 {
2964         struct service *service;
2965         struct chrc *chrc;
2966         DBusMessageIter iter;
2967         DBusMessageIter array;
2968         const char *uuid;
2969         char *flags[17];
2970         int i;
2971
2972         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
2973                 return;
2974
2975         dbus_message_iter_get_basic(&iter, &uuid);
2976
2977         if (g_dbus_proxy_get_property(proxy, "Flags", &iter) == FALSE)
2978                 return;
2979
2980         dbus_message_iter_recurse(&iter, &array);
2981
2982         for (i = 0; dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING;
2983                                                                         i++) {
2984                 dbus_message_iter_get_basic(&array, &flags[i]);
2985                 dbus_message_iter_next(&array);
2986         }
2987
2988         flags[i] = NULL;
2989
2990         service = g_list_last(local_services)->data;
2991
2992         chrc = g_new0(struct chrc, 1);
2993         chrc->service = service;
2994         chrc->proxy = proxy;
2995         chrc->uuid = g_strdup(uuid);
2996         chrc->path = g_strdup_printf("%s/chrc%u", service->path,
2997                                         g_list_length(service->chrcs));
2998         chrc->flags = g_strdupv(flags);
2999
3000         if (g_dbus_register_interface(service->conn, chrc->path, CHRC_INTERFACE,
3001                                         chrc_methods, NULL, chrc_properties,
3002                                         chrc, chrc_free) == FALSE) {
3003                 bt_shell_printf("Failed to register characteristic object\n");
3004                 chrc_free(chrc);
3005                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
3006         }
3007
3008         g_dbus_proxy_set_property_watch(proxy, proxy_property_changed, chrc);
3009
3010         service->chrcs = g_list_append(service->chrcs, chrc);
3011
3012         print_chrc(chrc, COLORED_NEW);
3013 }
3014
3015 static void clone_chrcs(struct GDBusProxy *proxy)
3016 {
3017         GList *l;
3018
3019         for (l = characteristics; l; l = g_list_next(l)) {
3020                 GDBusProxy *p = l->data;
3021
3022                 if (g_str_has_prefix(g_dbus_proxy_get_path(p),
3023                                                 g_dbus_proxy_get_path(proxy)))
3024                         clone_chrc(p);
3025         }
3026 }
3027
3028 static void clone_service(struct GDBusProxy *proxy)
3029 {
3030         struct service *service;
3031         DBusMessageIter iter;
3032         const char *uuid;
3033         dbus_bool_t primary;
3034
3035         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
3036                 return;
3037
3038         dbus_message_iter_get_basic(&iter, &uuid);
3039
3040         if (g_dbus_proxy_get_property(proxy, "Primary", &iter) == FALSE)
3041                 return;
3042
3043         dbus_message_iter_get_basic(&iter, &primary);
3044
3045         if (!strcmp(uuid, "00001800-0000-1000-8000-00805f9b34fb") ||
3046                         !strcmp(uuid, "00001801-0000-1000-8000-00805f9b34fb"))
3047                 return;
3048
3049         service = g_new0(struct service, 1);
3050         service->conn = bt_shell_get_env("DBUS_CONNECTION");
3051         service->proxy = proxy;
3052         service->path = g_strdup_printf("%s/service%u", APP_PATH,
3053                                         g_list_length(local_services));
3054         service->uuid = g_strdup(uuid);
3055         service->primary = primary;
3056
3057         if (g_dbus_register_interface(service->conn, service->path,
3058                                         SERVICE_INTERFACE, NULL, NULL,
3059                                         service_properties, service,
3060                                         service_free) == FALSE) {
3061                 bt_shell_printf("Failed to register service object\n");
3062                 service_free(service);
3063                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
3064         }
3065
3066         print_service(service, COLORED_NEW);
3067
3068         local_services = g_list_append(local_services, service);
3069
3070         clone_chrcs(proxy);
3071 }
3072
3073 static void clone_device(struct GDBusProxy *proxy)
3074 {
3075         GList *l;
3076
3077         for (l = services; l; l = g_list_next(l)) {
3078                 struct GDBusProxy *p = l->data;
3079
3080                 if (g_str_has_prefix(g_dbus_proxy_get_path(p),
3081                                                 g_dbus_proxy_get_path(proxy)))
3082                         clone_service(p);
3083         }
3084 }
3085
3086 static void service_clone(const char *input, void *user_data)
3087 {
3088         struct GDBusProxy *proxy = user_data;
3089
3090         if (!strcmp(input, "yes"))
3091                 return clone_service(proxy);
3092         else if (!strcmp(input, "no"))
3093                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
3094         else if (!strcmp(input, "all"))
3095                 return clone_device(proxy);
3096
3097         bt_shell_printf("Invalid option: %s\n", input);
3098
3099         return bt_shell_noninteractive_quit(EXIT_FAILURE);
3100 }
3101
3102 static void device_clone(const char *input, void *user_data)
3103 {
3104         struct GDBusProxy *proxy = user_data;
3105
3106         if (!strcmp(input, "yes"))
3107                 return clone_device(proxy);
3108         else if (!strcmp(input, "no"))
3109                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
3110
3111         bt_shell_printf("Invalid option: %s\n", input);
3112
3113         return bt_shell_noninteractive_quit(EXIT_FAILURE);
3114 }
3115
3116 static const char *proxy_get_name(struct GDBusProxy *proxy)
3117 {
3118         DBusMessageIter iter;
3119         const char *uuid;
3120         const char *str;
3121
3122         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
3123                 return NULL;
3124
3125         dbus_message_iter_get_basic(&iter, &uuid);
3126
3127         str = bt_uuidstr_to_str(uuid);
3128
3129         return str ? str : uuid;
3130 }
3131
3132 static const char *proxy_get_alias(struct GDBusProxy *proxy)
3133 {
3134         DBusMessageIter iter;
3135         const char *alias;
3136
3137         if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == FALSE)
3138                 return NULL;
3139
3140         dbus_message_iter_get_basic(&iter, &alias);
3141
3142         return alias;
3143 }
3144
3145 void gatt_clone_attribute(GDBusProxy *proxy, int argc, char *argv[])
3146 {
3147         GDBusProxy *service = NULL;
3148
3149         if (argc > 1) {
3150                 proxy = gatt_select_attribute(proxy, argv[1]);
3151                 if (!proxy) {
3152                         bt_shell_printf("Unable to find attribute %s\n",
3153                                                                 argv[1]);
3154                         return bt_shell_noninteractive_quit(EXIT_FAILURE);
3155                 }
3156         }
3157
3158         if (!strcmp(g_dbus_proxy_get_interface(proxy), DEVICE_INTERFACE)) {
3159                 bt_shell_prompt_input(proxy_get_alias(proxy),
3160                                         "Clone (yes/no):",
3161                                         device_clone, proxy);
3162         }
3163
3164         /* Only clone services */
3165         service = select_service(proxy);
3166         if (service) {
3167                 bt_shell_prompt_input(proxy_get_name(proxy),
3168                                         "Clone (yes/no/all):",
3169                                         service_clone, service);
3170                 return;
3171         }
3172
3173         return bt_shell_noninteractive_quit(EXIT_FAILURE);
3174 }