Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / client / gatt.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2014  Intel Corporation. All rights reserved.
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <stdbool.h>
33 #include <sys/uio.h>
34 #include <wordexp.h>
35
36 #include <readline/readline.h>
37 #include <readline/history.h>
38 #include <glib.h>
39
40 #include "gdbus/gdbus.h"
41 #include "monitor/uuid.h"
42 #include "display.h"
43 #include "gatt.h"
44
45 #define PROFILE_PATH "/org/bluez/profile"
46 #define PROFILE_INTERFACE "org.bluez.GattProfile1"
47
48 /* String display constants */
49 #define COLORED_NEW     COLOR_GREEN "NEW" COLOR_OFF
50 #define COLORED_CHG     COLOR_YELLOW "CHG" COLOR_OFF
51 #define COLORED_DEL     COLOR_RED "DEL" COLOR_OFF
52
53 static GList *services;
54 static GList *characteristics;
55 static GList *descriptors;
56 static GList *managers;
57
58 static void print_service(GDBusProxy *proxy, const char *description)
59 {
60         DBusMessageIter iter;
61         const char *uuid, *text;
62         dbus_bool_t primary;
63
64         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
65                 return;
66
67         dbus_message_iter_get_basic(&iter, &uuid);
68
69         if (g_dbus_proxy_get_property(proxy, "Primary", &iter) == FALSE)
70                 return;
71
72         dbus_message_iter_get_basic(&iter, &primary);
73
74         text = uuidstr_to_str(uuid);
75         if (!text)
76                 text = uuid;
77
78         rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n",
79                                 description ? "[" : "",
80                                 description ? : "",
81                                 description ? "] " : "",
82                                 primary ? "Primary" : "Secondary",
83                                 g_dbus_proxy_get_path(proxy),
84                                 text);
85 }
86
87 void gatt_add_service(GDBusProxy *proxy)
88 {
89         services = g_list_append(services, proxy);
90
91         print_service(proxy, COLORED_NEW);
92 }
93
94 void gatt_remove_service(GDBusProxy *proxy)
95 {
96         GList *l;
97
98         l = g_list_find(services, proxy);
99         if (!l)
100                 return;
101
102         services = g_list_delete_link(services, l);
103
104         print_service(proxy, COLORED_DEL);
105 }
106
107 static void print_characteristic(GDBusProxy *proxy, const char *description)
108 {
109         DBusMessageIter iter;
110         const char *uuid, *text;
111
112         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
113                 return;
114
115         dbus_message_iter_get_basic(&iter, &uuid);
116
117         text = uuidstr_to_str(uuid);
118         if (!text)
119                 text = uuid;
120
121         rl_printf("%s%s%sCharacteristic\n\t%s\n\t%s\n",
122                                 description ? "[" : "",
123                                 description ? : "",
124                                 description ? "] " : "",
125                                 g_dbus_proxy_get_path(proxy),
126                                 text);
127 }
128
129 static gboolean characteristic_is_child(GDBusProxy *characteristic)
130 {
131         GList *l;
132         DBusMessageIter iter;
133         const char *service, *path;
134
135         if (!g_dbus_proxy_get_property(characteristic, "Service", &iter))
136                 return FALSE;
137
138         dbus_message_iter_get_basic(&iter, &service);
139
140         for (l = services; l; l = g_list_next(l)) {
141                 GDBusProxy *proxy = l->data;
142
143                 path = g_dbus_proxy_get_path(proxy);
144
145                 if (!strcmp(path, service))
146                         return TRUE;
147         }
148
149         return FALSE;
150 }
151
152 void gatt_add_characteristic(GDBusProxy *proxy)
153 {
154         if (!characteristic_is_child(proxy))
155                 return;
156
157         characteristics = g_list_append(characteristics, proxy);
158
159         print_characteristic(proxy, COLORED_NEW);
160 }
161
162 void gatt_remove_characteristic(GDBusProxy *proxy)
163 {
164         GList *l;
165
166         l = g_list_find(characteristics, proxy);
167         if (!l)
168                 return;
169
170         characteristics = g_list_delete_link(characteristics, l);
171
172         print_characteristic(proxy, COLORED_DEL);
173 }
174
175 static void print_descriptor(GDBusProxy *proxy, const char *description)
176 {
177         DBusMessageIter iter;
178         const char *uuid, *text;
179
180         if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
181                 return;
182
183         dbus_message_iter_get_basic(&iter, &uuid);
184
185         text = uuidstr_to_str(uuid);
186         if (!text)
187                 text = uuid;
188
189         rl_printf("%s%s%sDescriptor\n\t%s\n\t%s\n",
190                                 description ? "[" : "",
191                                 description ? : "",
192                                 description ? "] " : "",
193                                 g_dbus_proxy_get_path(proxy),
194                                 text);
195 }
196
197 static gboolean descriptor_is_child(GDBusProxy *characteristic)
198 {
199         GList *l;
200         DBusMessageIter iter;
201         const char *service, *path;
202
203         if (!g_dbus_proxy_get_property(characteristic, "Characteristic", &iter))
204                 return FALSE;
205
206         dbus_message_iter_get_basic(&iter, &service);
207
208         for (l = characteristics; l; l = g_list_next(l)) {
209                 GDBusProxy *proxy = l->data;
210
211                 path = g_dbus_proxy_get_path(proxy);
212
213                 if (!strcmp(path, service))
214                         return TRUE;
215         }
216
217         return FALSE;
218 }
219
220 void gatt_add_descriptor(GDBusProxy *proxy)
221 {
222         if (!descriptor_is_child(proxy))
223                 return;
224
225         descriptors = g_list_append(descriptors, proxy);
226
227         print_descriptor(proxy, COLORED_NEW);
228 }
229
230 void gatt_remove_descriptor(GDBusProxy *proxy)
231 {
232         GList *l;
233
234         l = g_list_find(descriptors, proxy);
235         if (!l)
236                 return;
237
238         descriptors = g_list_delete_link(descriptors, l);
239
240         print_descriptor(proxy, COLORED_DEL);
241 }
242
243 static void list_attributes(const char *path, GList *source)
244 {
245         GList *l;
246
247         for (l = source; l; l = g_list_next(l)) {
248                 GDBusProxy *proxy = l->data;
249                 const char *proxy_path;
250
251                 proxy_path = g_dbus_proxy_get_path(proxy);
252
253                 if (!g_str_has_prefix(proxy_path, path))
254                         continue;
255
256                 if (source == services) {
257                         print_service(proxy, NULL);
258                         list_attributes(proxy_path, characteristics);
259                 } else if (source == characteristics) {
260                         print_characteristic(proxy, NULL);
261                         list_attributes(proxy_path, descriptors);
262                 } else if (source == descriptors)
263                         print_descriptor(proxy, NULL);
264         }
265 }
266
267 void gatt_list_attributes(const char *path)
268 {
269         list_attributes(path, services);
270 }
271
272 static GDBusProxy *select_proxy(const char *path, GList *source)
273 {
274         GList *l;
275
276         for (l = source; l; l = g_list_next(l)) {
277                 GDBusProxy *proxy = l->data;
278
279                 if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
280                         return proxy;
281         }
282
283         return NULL;
284 }
285
286 GDBusProxy *gatt_select_attribute(const char *path)
287 {
288         GDBusProxy *proxy;
289
290         proxy = select_proxy(path, services);
291         if (proxy)
292                 return proxy;
293
294         proxy = select_proxy(path, characteristics);
295         if (proxy)
296                 return proxy;
297
298         return select_proxy(path, descriptors);
299 }
300
301 static char *attribute_generator(const char *text, int state, GList *source)
302 {
303         static int index, len;
304         GList *list;
305
306         if (!state) {
307                 index = 0;
308                 len = strlen(text);
309         }
310
311         for (list = g_list_nth(source, index); list;
312                                                 list = g_list_next(list)) {
313                 GDBusProxy *proxy = list->data;
314                 const char *path;
315
316                 index++;
317
318                 path = g_dbus_proxy_get_path(proxy);
319
320                 if (!strncmp(path, text, len))
321                         return strdup(path);
322         }
323
324         return NULL;
325 }
326
327 char *gatt_attribute_generator(const char *text, int state)
328 {
329         static GList *list = NULL;
330
331         if (!state) {
332                 GList *list1;
333
334                 if (list) {
335                         g_list_free(list);
336                         list = NULL;
337                 }
338
339                 list1 = g_list_copy(characteristics);
340                 list1 = g_list_concat(list1, g_list_copy(descriptors));
341
342                 list = g_list_copy(services);
343                 list = g_list_concat(list, list1);
344         }
345
346         return attribute_generator(text, state, list);
347 }
348
349 static void read_reply(DBusMessage *message, void *user_data)
350 {
351         DBusError error;
352         DBusMessageIter iter, array;
353         uint8_t *value;
354         int len;
355
356         dbus_error_init(&error);
357
358         if (dbus_set_error_from_message(&error, message) == TRUE) {
359                 rl_printf("Failed to read: %s\n", error.name);
360                 dbus_error_free(&error);
361                 return;
362         }
363
364         dbus_message_iter_init(message, &iter);
365
366         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
367                 rl_printf("Invalid response to read\n");
368                 return;
369         }
370
371         dbus_message_iter_recurse(&iter, &array);
372         dbus_message_iter_get_fixed_array(&array, &value, &len);
373
374         if (len < 0) {
375                 rl_printf("Unable to parse value\n");
376                 return;
377         }
378
379         rl_hexdump(value, len);
380 }
381
382 static void read_attribute(GDBusProxy *proxy)
383 {
384         if (g_dbus_proxy_method_call(proxy, "ReadValue", NULL, read_reply,
385                                                         NULL, NULL) == FALSE) {
386                 rl_printf("Failed to read\n");
387                 return;
388         }
389
390         rl_printf("Attempting to read %s\n", g_dbus_proxy_get_path(proxy));
391 }
392
393 void gatt_read_attribute(GDBusProxy *proxy)
394 {
395         const char *iface;
396
397         iface = g_dbus_proxy_get_interface(proxy);
398         if (!strcmp(iface, "org.bluez.GattCharacteristic1") ||
399                                 !strcmp(iface, "org.bluez.GattDescriptor1")) {
400                 read_attribute(proxy);
401                 return;
402         }
403
404         rl_printf("Unable to read attribute %s\n",
405                                                 g_dbus_proxy_get_path(proxy));
406 }
407
408 static void write_reply(DBusMessage *message, void *user_data)
409 {
410         DBusError error;
411
412         dbus_error_init(&error);
413
414         if (dbus_set_error_from_message(&error, message) == TRUE) {
415                 rl_printf("Failed to write: %s\n", error.name);
416                 dbus_error_free(&error);
417                 return;
418         }
419 }
420
421 static void write_setup(DBusMessageIter *iter, void *user_data)
422 {
423         struct iovec *iov = user_data;
424         DBusMessageIter array;
425
426         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
427         dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
428                                                 &iov->iov_base, iov->iov_len);
429         dbus_message_iter_close_container(iter, &array);
430 }
431
432 static void write_attribute(GDBusProxy *proxy, char *arg)
433 {
434         struct iovec iov;
435         uint8_t value[512];
436         char *entry;
437         unsigned int i;
438
439         for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) {
440                 long int val;
441                 char *endptr = NULL;
442
443                 if (*entry == '\0')
444                         continue;
445
446                 if (i >= G_N_ELEMENTS(value)) {
447                         rl_printf("Too much data\n");
448                         return;
449                 }
450
451                 val = strtol(entry, &endptr, 0);
452                 if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
453                         rl_printf("Invalid value at index %d\n", i);
454                         return;
455                 }
456
457                 value[i] = val;
458         }
459
460         iov.iov_base = value;
461         iov.iov_len = i;
462
463         if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup,
464                                         write_reply, &iov, NULL) == FALSE) {
465                 rl_printf("Failed to write\n");
466                 return;
467         }
468
469         rl_printf("Attempting to write %s\n", g_dbus_proxy_get_path(proxy));
470 }
471
472 void gatt_write_attribute(GDBusProxy *proxy, const char *arg)
473 {
474         const char *iface;
475
476         iface = g_dbus_proxy_get_interface(proxy);
477         if (!strcmp(iface, "org.bluez.GattCharacteristic1") ||
478                                 !strcmp(iface, "org.bluez.GattDescriptor1")) {
479                 write_attribute(proxy, (char *) arg);
480                 return;
481         }
482
483         rl_printf("Unable to write attribute %s\n",
484                                                 g_dbus_proxy_get_path(proxy));
485 }
486
487 static void notify_reply(DBusMessage *message, void *user_data)
488 {
489         bool enable = GPOINTER_TO_UINT(user_data);
490         DBusError error;
491
492         dbus_error_init(&error);
493
494         if (dbus_set_error_from_message(&error, message) == TRUE) {
495                 rl_printf("Failed to %s notify: %s\n",
496                                 enable ? "start" : "stop", error.name);
497                 dbus_error_free(&error);
498                 return;
499         }
500
501         rl_printf("Notify %s\n", enable == TRUE ? "started" : "stopped");
502 }
503
504 static void notify_attribute(GDBusProxy *proxy, bool enable)
505 {
506         const char *method;
507
508         if (enable == TRUE)
509                 method = "StartNotify";
510         else
511                 method = "StopNotify";
512
513         if (g_dbus_proxy_method_call(proxy, method, NULL, notify_reply,
514                                 GUINT_TO_POINTER(enable), NULL) == FALSE) {
515                 rl_printf("Failed to %s notify\n", enable ? "start" : "stop");
516                 return;
517         }
518 }
519
520 void gatt_notify_attribute(GDBusProxy *proxy, bool enable)
521 {
522         const char *iface;
523
524         iface = g_dbus_proxy_get_interface(proxy);
525         if (!strcmp(iface, "org.bluez.GattCharacteristic1")) {
526                 notify_attribute(proxy, enable);
527                 return;
528         }
529
530         rl_printf("Unable to notify attribute %s\n",
531                                                 g_dbus_proxy_get_path(proxy));
532 }
533
534 static void register_profile_setup(DBusMessageIter *iter, void *user_data)
535 {
536         wordexp_t *w = user_data;
537         DBusMessageIter uuids, opt;
538         const char *path = PROFILE_PATH;
539         size_t i;
540
541         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
542
543         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &uuids);
544         for (i = 0; i < w->we_wordc; i++)
545                 dbus_message_iter_append_basic(&uuids, DBUS_TYPE_STRING,
546                                                         &w->we_wordv[i]);
547         dbus_message_iter_close_container(iter, &uuids);
548
549         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
550                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
551                                         DBUS_TYPE_STRING_AS_STRING
552                                         DBUS_TYPE_VARIANT_AS_STRING
553                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
554                                         &opt);
555         dbus_message_iter_close_container(iter, &opt);
556
557 }
558
559 static void register_profile_reply(DBusMessage *message, void *user_data)
560 {
561         DBusError error;
562
563         dbus_error_init(&error);
564
565         if (dbus_set_error_from_message(&error, message) == TRUE) {
566                 rl_printf("Failed to register profile: %s\n", error.name);
567                 dbus_error_free(&error);
568                 return;
569         }
570
571         rl_printf("Profile registered\n");
572 }
573
574 void gatt_add_manager(GDBusProxy *proxy)
575 {
576         managers = g_list_append(managers, proxy);
577 }
578
579 void gatt_remove_manager(GDBusProxy *proxy)
580 {
581         managers = g_list_remove(managers, proxy);
582 }
583
584 static int match_proxy(const void *a, const void *b)
585 {
586         GDBusProxy *proxy1 = (void *) a;
587         GDBusProxy *proxy2 = (void *) b;
588
589         return strcmp(g_dbus_proxy_get_path(proxy1),
590                                                 g_dbus_proxy_get_path(proxy2));
591 }
592
593 static DBusMessage *release_profile(DBusConnection *conn,
594                                         DBusMessage *msg, void *user_data)
595 {
596         g_dbus_unregister_interface(conn, PROFILE_PATH, PROFILE_INTERFACE);
597
598         return dbus_message_new_method_return(msg);
599 }
600
601 static const GDBusMethodTable methods[] = {
602         { GDBUS_METHOD("Release", NULL, NULL, release_profile) },
603         { }
604 };
605
606 void gatt_register_profile(DBusConnection *conn, GDBusProxy *proxy,
607                                                                 wordexp_t *w)
608 {
609         GList *l;
610
611         l = g_list_find_custom(managers, proxy, match_proxy);
612         if (!l) {
613                 rl_printf("Unable to find GattManager proxy\n");
614                 return;
615         }
616
617         if (g_dbus_register_interface(conn, PROFILE_PATH,
618                                         PROFILE_INTERFACE, methods,
619                                         NULL, NULL, NULL, NULL) == FALSE) {
620                 rl_printf("Failed to register profile object\n");
621                 return;
622         }
623
624         if (g_dbus_proxy_method_call(l->data, "RegisterProfile",
625                                                 register_profile_setup,
626                                                 register_profile_reply, w,
627                                                 NULL) == FALSE) {
628                 rl_printf("Failed register profile\n");
629                 return;
630         }
631 }
632
633 static void unregister_profile_reply(DBusMessage *message, void *user_data)
634 {
635         DBusConnection *conn = user_data;
636         DBusError error;
637
638         dbus_error_init(&error);
639
640         if (dbus_set_error_from_message(&error, message) == TRUE) {
641                 rl_printf("Failed to unregister profile: %s\n", error.name);
642                 dbus_error_free(&error);
643                 return;
644         }
645
646         rl_printf("Profile unregistered\n");
647
648         g_dbus_unregister_interface(conn, PROFILE_PATH, PROFILE_INTERFACE);
649 }
650
651 static void unregister_profile_setup(DBusMessageIter *iter, void *user_data)
652 {
653         const char *path = PROFILE_PATH;
654
655         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
656 }
657
658 void gatt_unregister_profile(DBusConnection *conn, GDBusProxy *proxy)
659 {
660         GList *l;
661
662         l = g_list_find_custom(managers, proxy, match_proxy);
663         if (!l) {
664                 rl_printf("Unable to find GattManager proxy\n");
665                 return;
666         }
667
668         if (g_dbus_proxy_method_call(l->data, "UnregisterProfile",
669                                                 unregister_profile_setup,
670                                                 unregister_profile_reply, conn,
671                                                 NULL) == FALSE) {
672                 rl_printf("Failed unregister profile\n");
673                 return;
674         }
675 }