1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2010 Nokia Corporation
6 * Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <glib.h>
33
34 #include <bluetooth/bluetooth.h>
35 #include <bluetooth/uuid.h>
36
37 #include "adapter.h"
38 #include "device.h"
39 #include "log.h"
40 #include "gdbus.h"
41 #include "error.h"
42 #include "dbus-common.h"
43 #include "btio.h"
44 #include "storage.h"
45
46 #include "att.h"
47 #include "gattrib.h"
48 #include "gatt.h"
49 #include "client.h"
50
51 #define CHAR_INTERFACE "org.bluez.Characteristic"
52
53 struct gatt_service {
54 struct btd_device *dev;
55 DBusConnection *conn;
56 bdaddr_t sba;
57 bdaddr_t dba;
58 char *path;
59 GSList *primary;
60 GAttrib *attrib;
61 DBusMessage *msg;
62 int psm;
63 gboolean listen;
64 };
65
66 struct format {
67 guint8 format;
68 guint8 exponent;
69 guint16 unit;
70 guint8 namespace;
71 guint16 desc;
72 } __attribute__ ((packed));
73
74 struct primary {
75 struct gatt_service *gatt;
76 struct att_primary *att;
77 char *path;
78 GSList *chars;
79 GSList *watchers;
80 };
81
82 struct characteristic {
83 struct primary *prim;
84 char *path;
85 uint16_t handle;
86 uint16_t end;
87 uint8_t perm;
88 char type[MAX_LEN_UUID_STR + 1];
89 char *name;
90 char *desc;
91 struct format *format;
92 uint8_t *value;
93 size_t vlen;
94 };
95
96 struct query_data {
97 struct primary *prim;
98 struct characteristic *chr;
99 DBusMessage *msg;
100 uint16_t handle;
101 };
102
103 struct watcher {
104 guint id;
105 char *name;
106 char *path;
107 struct primary *prim;
108 };
109
110 static GSList *gatt_services = NULL;
111
characteristic_free(void * user_data)112 static void characteristic_free(void *user_data)
113 {
114 struct characteristic *chr = user_data;
115
116 g_free(chr->path);
117 g_free(chr->desc);
118 g_free(chr->format);
119 g_free(chr->value);
120 g_free(chr->name);
121 g_free(chr);
122 }
123
watcher_free(void * user_data)124 static void watcher_free(void *user_data)
125 {
126 struct watcher *watcher = user_data;
127
128 g_free(watcher->path);
129 g_free(watcher->name);
130 g_free(watcher);
131 }
132
primary_free(void * user_data)133 static void primary_free(void *user_data)
134 {
135 struct primary *prim = user_data;
136 GSList *l;
137
138 for (l = prim->watchers; l; l = l->next) {
139 struct watcher *watcher = l->data;
140 g_dbus_remove_watch(prim->gatt->conn, watcher->id);
141 }
142
143 g_slist_foreach(prim->chars, (GFunc) characteristic_free, NULL);
144 g_slist_free(prim->chars);
145 g_free(prim->path);
146 g_free(prim);
147 }
148
gatt_service_free(void * user_data)149 static void gatt_service_free(void *user_data)
150 {
151 struct gatt_service *gatt = user_data;
152
153 g_slist_foreach(gatt->primary, (GFunc) primary_free, NULL);
154 g_slist_free(gatt->primary);
155 g_attrib_unref(gatt->attrib);
156 g_free(gatt->path);
157 btd_device_unref(gatt->dev);
158 dbus_connection_unref(gatt->conn);
159 g_free(gatt);
160 }
161
gatt_dev_cmp(gconstpointer a,gconstpointer b)162 static int gatt_dev_cmp(gconstpointer a, gconstpointer b)
163 {
164 const struct gatt_service *gatt = a;
165 const struct btd_device *dev = b;
166
167 return gatt->dev != dev;
168 }
169
characteristic_handle_cmp(gconstpointer a,gconstpointer b)170 static int characteristic_handle_cmp(gconstpointer a, gconstpointer b)
171 {
172 const struct characteristic *chr = a;
173 uint16_t handle = GPOINTER_TO_UINT(b);
174
175 return chr->handle - handle;
176 }
177
watcher_cmp(gconstpointer a,gconstpointer b)178 static int watcher_cmp(gconstpointer a, gconstpointer b)
179 {
180 const struct watcher *watcher = a;
181 const struct watcher *match = b;
182 int ret;
183
184 ret = g_strcmp0(watcher->name, match->name);
185 if (ret != 0)
186 return ret;
187
188 return g_strcmp0(watcher->path, match->path);
189 }
190
append_char_dict(DBusMessageIter * iter,struct characteristic * chr)191 static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
192 {
193 DBusMessageIter dict;
194 const char *name = "";
195 char *uuid;
196
197 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
198 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
199 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
200 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
201
202 uuid = g_strdup(chr->type);
203 dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
204 g_free(uuid);
205
206 /* FIXME: Translate UUID to name. */
207 dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &name);
208
209 if (chr->desc)
210 dict_append_entry(&dict, "Description", DBUS_TYPE_STRING,
211 &chr->desc);
212
213 if (chr->value)
214 dict_append_array(&dict, "Value", DBUS_TYPE_BYTE, &chr->value,
215 chr->vlen);
216
217 /* FIXME: Missing Format, Value and Representation */
218
219 dbus_message_iter_close_container(iter, &dict);
220 }
221
watcher_exit(DBusConnection * conn,void * user_data)222 static void watcher_exit(DBusConnection *conn, void *user_data)
223 {
224 struct watcher *watcher = user_data;
225 struct primary *prim = watcher->prim;
226 struct gatt_service *gatt = prim->gatt;
227
228 DBG("%s watcher %s exited", prim->path, watcher->name);
229
230 prim->watchers = g_slist_remove(prim->watchers, watcher);
231
232 g_attrib_unref(gatt->attrib);
233 }
234
characteristic_set_value(struct characteristic * chr,const uint8_t * value,size_t vlen)235 static int characteristic_set_value(struct characteristic *chr,
236 const uint8_t *value, size_t vlen)
237 {
238 chr->value = g_try_realloc(chr->value, vlen);
239 if (chr->value == NULL)
240 return -ENOMEM;
241
242 memcpy(chr->value, value, vlen);
243 chr->vlen = vlen;
244
245 return 0;
246 }
247
update_watchers(gpointer data,gpointer user_data)248 static void update_watchers(gpointer data, gpointer user_data)
249 {
250 struct watcher *w = data;
251 struct characteristic *chr = user_data;
252 DBusConnection *conn = w->prim->gatt->conn;
253 DBusMessage *msg;
254
255 msg = dbus_message_new_method_call(w->name, w->path,
256 "org.bluez.Watcher", "ValueChanged");
257 if (msg == NULL)
258 return;
259
260 dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &chr->path,
261 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
262 &chr->value, chr->vlen, DBUS_TYPE_INVALID);
263
264 dbus_message_set_no_reply(msg, TRUE);
265 g_dbus_send_message(conn, msg);
266 }
267
events_handler(const uint8_t * pdu,uint16_t len,gpointer user_data)268 static void events_handler(const uint8_t *pdu, uint16_t len,
269 gpointer user_data)
270 {
271 struct gatt_service *gatt = user_data;
272 struct characteristic *chr;
273 struct primary *prim;
274 GSList *lprim, *lchr;
275 uint8_t opdu[ATT_MAX_MTU];
276 guint handle;
277 uint16_t olen;
278
279 if (len < 3) {
280 DBG("Malformed notification/indication packet (opcode 0x%02x)",
281 pdu[0]);
282 return;
283 }
284
285 handle = att_get_u16(&pdu[1]);
286
287 for (lprim = gatt->primary, prim = NULL, chr = NULL; lprim;
288 lprim = lprim->next) {
289 prim = lprim->data;
290
291 lchr = g_slist_find_custom(prim->chars,
292 GUINT_TO_POINTER(handle), characteristic_handle_cmp);
293 if (lchr) {
294 chr = lchr->data;
295 break;
296 }
297 }
298
299 if (chr == NULL) {
300 DBG("Attribute handle 0x%02x not found", handle);
301 return;
302 }
303
304 switch (pdu[0]) {
305 case ATT_OP_HANDLE_IND:
306 olen = enc_confirmation(opdu, sizeof(opdu));
307 g_attrib_send(gatt->attrib, 0, opdu[0], opdu, olen,
308 NULL, NULL, NULL);
309 case ATT_OP_HANDLE_NOTIFY:
310 if (characteristic_set_value(chr, &pdu[3], len - 3) < 0)
311 DBG("Can't change Characteristic 0x%02x", handle);
312
313 g_slist_foreach(prim->watchers, update_watchers, chr);
314 break;
315 }
316 }
317
attrib_destroy(gpointer user_data)318 static void attrib_destroy(gpointer user_data)
319 {
320 struct gatt_service *gatt = user_data;
321
322 gatt->attrib = NULL;
323 }
324
attrib_disconnect(gpointer user_data)325 static void attrib_disconnect(gpointer user_data)
326 {
327 struct gatt_service *gatt = user_data;
328
329 /* Remote initiated disconnection only */
330 g_attrib_unref(gatt->attrib);
331 }
332
connect_cb(GIOChannel * chan,GError * gerr,gpointer user_data)333 static void connect_cb(GIOChannel *chan, GError *gerr, gpointer user_data)
334 {
335 struct gatt_service *gatt = user_data;
336
337 if (gerr) {
338 if (gatt->msg) {
339 DBusMessage *reply = btd_error_failed(gatt->msg,
340 gerr->message);
341 g_dbus_send_message(gatt->conn, reply);
342 }
343
344 error("%s", gerr->message);
345 goto fail;
346 }
347
348 if (gatt->attrib == NULL)
349 return;
350
351 /* Listen mode: used for notification and indication */
352 if (gatt->listen == TRUE) {
353 g_attrib_register(gatt->attrib,
354 ATT_OP_HANDLE_NOTIFY,
355 events_handler, gatt, NULL);
356 g_attrib_register(gatt->attrib,
357 ATT_OP_HANDLE_IND,
358 events_handler, gatt, NULL);
359 return;
360 }
361
362 return;
363 fail:
364 g_attrib_unref(gatt->attrib);
365 }
366
l2cap_connect(struct gatt_service * gatt,GError ** gerr,gboolean listen)367 static int l2cap_connect(struct gatt_service *gatt, GError **gerr,
368 gboolean listen)
369 {
370 GIOChannel *io;
371
372 if (gatt->attrib != NULL) {
373 gatt->attrib = g_attrib_ref(gatt->attrib);
374 gatt->listen = listen;
375 return 0;
376 }
377
378 /*
379 * FIXME: If the service doesn't support Client Characteristic
380 * Configuration it is necessary to poll the server from time
381 * to time checking for modifications.
382 */
383 if (gatt->psm < 0)
384 io = bt_io_connect(BT_IO_L2CAP, connect_cb, gatt, NULL, gerr,
385 BT_IO_OPT_SOURCE_BDADDR, &gatt->sba,
386 BT_IO_OPT_DEST_BDADDR, &gatt->dba,
387 BT_IO_OPT_CID, ATT_CID,
388 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
389 BT_IO_OPT_INVALID);
390 else
391 io = bt_io_connect(BT_IO_L2CAP, connect_cb, gatt, NULL, gerr,
392 BT_IO_OPT_SOURCE_BDADDR, &gatt->sba,
393 BT_IO_OPT_DEST_BDADDR, &gatt->dba,
394 BT_IO_OPT_PSM, gatt->psm,
395 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
396 BT_IO_OPT_INVALID);
397 if (!io)
398 return -1;
399
400 gatt->attrib = g_attrib_new(io);
401 g_io_channel_unref(io);
402 gatt->listen = listen;
403
404 g_attrib_set_destroy_function(gatt->attrib, attrib_destroy, gatt);
405 g_attrib_set_disconnect_function(gatt->attrib, attrib_disconnect,
406 gatt);
407
408 return 0;
409 }
410
register_watcher(DBusConnection * conn,DBusMessage * msg,void * data)411 static DBusMessage *register_watcher(DBusConnection *conn,
412 DBusMessage *msg, void *data)
413 {
414 const char *sender = dbus_message_get_sender(msg);
415 struct primary *prim = data;
416 struct watcher *watcher;
417 GError *gerr = NULL;
418 char *path;
419
420 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
421 DBUS_TYPE_INVALID))
422 return btd_error_invalid_args(msg);
423
424 if (l2cap_connect(prim->gatt, &gerr, TRUE) < 0) {
425 DBusMessage *reply = btd_error_failed(msg, gerr->message);
426 g_error_free(gerr);
427 return reply;
428 }
429
430 watcher = g_new0(struct watcher, 1);
431 watcher->name = g_strdup(sender);
432 watcher->prim = prim;
433 watcher->path = g_strdup(path);
434 watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
435 watcher, watcher_free);
436
437 prim->watchers = g_slist_append(prim->watchers, watcher);
438
439 return dbus_message_new_method_return(msg);
440 }
441
unregister_watcher(DBusConnection * conn,DBusMessage * msg,void * data)442 static DBusMessage *unregister_watcher(DBusConnection *conn,
443 DBusMessage *msg, void *data)
444 {
445 const char *sender = dbus_message_get_sender(msg);
446 struct primary *prim = data;
447 struct watcher *watcher, *match;
448 GSList *l;
449 char *path;
450
451 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
452 DBUS_TYPE_INVALID))
453 return btd_error_invalid_args(msg);
454
455 match = g_new0(struct watcher, 1);
456 match->name = g_strdup(sender);
457 match->path = g_strdup(path);
458 l = g_slist_find_custom(prim->watchers, match, watcher_cmp);
459 watcher_free(match);
460 if (!l)
461 return btd_error_not_authorized(msg);
462
463 watcher = l->data;
464 g_dbus_remove_watch(conn, watcher->id);
465 prim->watchers = g_slist_remove(prim->watchers, watcher);
466 watcher_free(watcher);
467
468 return dbus_message_new_method_return(msg);
469 }
470
set_value(DBusConnection * conn,DBusMessage * msg,DBusMessageIter * iter,struct characteristic * chr)471 static DBusMessage *set_value(DBusConnection *conn, DBusMessage *msg,
472 DBusMessageIter *iter, struct characteristic *chr)
473 {
474 struct gatt_service *gatt = chr->prim->gatt;
475 DBusMessageIter sub;
476 GError *gerr = NULL;
477 uint8_t *value;
478 int len;
479
480 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
481 dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
482 return btd_error_invalid_args(msg);
483
484 dbus_message_iter_recurse(iter, &sub);
485
486 dbus_message_iter_get_fixed_array(&sub, &value, &len);
487
488 if (l2cap_connect(gatt, &gerr, FALSE) < 0) {
489 DBusMessage *reply = btd_error_failed(msg, gerr->message);
490 g_error_free(gerr);
491 return reply;
492 }
493
494 gatt_write_cmd(gatt->attrib, chr->handle, value, len, NULL, NULL);
495
496 characteristic_set_value(chr, value, len);
497
498 return dbus_message_new_method_return(msg);
499 }
500
get_properties(DBusConnection * conn,DBusMessage * msg,void * data)501 static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
502 void *data)
503 {
504 struct characteristic *chr = data;
505 DBusMessage *reply;
506 DBusMessageIter iter;
507
508 reply = dbus_message_new_method_return(msg);
509 if (!reply)
510 return NULL;
511
512 dbus_message_iter_init_append(reply, &iter);
513
514 append_char_dict(&iter, chr);
515
516 return reply;
517 }
518
set_property(DBusConnection * conn,DBusMessage * msg,void * data)519 static DBusMessage *set_property(DBusConnection *conn,
520 DBusMessage *msg, void *data)
521 {
522 struct characteristic *chr = data;
523 DBusMessageIter iter;
524 DBusMessageIter sub;
525 const char *property;
526
527 if (!dbus_message_iter_init(msg, &iter))
528 return btd_error_invalid_args(msg);
529
530 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
531 return btd_error_invalid_args(msg);
532
533 dbus_message_iter_get_basic(&iter, &property);
534 dbus_message_iter_next(&iter);
535
536 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
537 return btd_error_invalid_args(msg);
538
539 dbus_message_iter_recurse(&iter, &sub);
540
541 if (g_str_equal("Value", property))
542 return set_value(conn, msg, &sub, chr);
543
544 return btd_error_invalid_args(msg);
545 }
546
547 static GDBusMethodTable char_methods[] = {
548 { "GetProperties", "", "a{sv}", get_properties },
549 { "SetProperty", "sv", "", set_property,
550 G_DBUS_METHOD_FLAG_ASYNC},
551 { }
552 };
553
characteristic_list_to_string(GSList * chars)554 static char *characteristic_list_to_string(GSList *chars)
555 {
556 GString *characteristics;
557 GSList *l;
558
559 characteristics = g_string_new(NULL);
560
561 for (l = chars; l; l = l->next) {
562 struct characteristic *chr = l->data;
563 char chr_str[64];
564
565 memset(chr_str, 0, sizeof(chr_str));
566
567 snprintf(chr_str, sizeof(chr_str), "%04X#%02X#%04X#%s ",
568 chr->handle, chr->perm, chr->end, chr->type);
569
570 characteristics = g_string_append(characteristics, chr_str);
571 }
572
573 return g_string_free(characteristics, FALSE);
574 }
575
store_characteristics(struct gatt_service * gatt,struct primary * prim)576 static void store_characteristics(struct gatt_service *gatt,
577 struct primary *prim)
578 {
579 char *characteristics;
580 struct att_primary *att = prim->att;
581
582 characteristics = characteristic_list_to_string(prim->chars);
583
584 write_device_characteristics(&gatt->sba, &gatt->dba, att->start,
585 characteristics);
586
587 g_free(characteristics);
588 }
589
register_characteristics(struct primary * prim)590 static void register_characteristics(struct primary *prim)
591 {
592 GSList *lc;
593
594 for (lc = prim->chars; lc; lc = lc->next) {
595 struct characteristic *chr = lc->data;
596 g_dbus_register_interface(prim->gatt->conn, chr->path,
597 CHAR_INTERFACE, char_methods,
598 NULL, NULL, chr, NULL);
599 DBG("Registered: %s", chr->path);
600 }
601 }
602
string_to_characteristic_list(struct primary * prim,const char * str)603 static GSList *string_to_characteristic_list(struct primary *prim,
604 const char *str)
605 {
606 GSList *l = NULL;
607 char **chars;
608 int i;
609
610 if (str == NULL)
611 return NULL;
612
613 chars = g_strsplit(str, " ", 0);
614 if (chars == NULL)
615 return NULL;
616
617 for (i = 0; chars[i]; i++) {
618 struct characteristic *chr;
619 int ret;
620
621 chr = g_new0(struct characteristic, 1);
622
623 ret = sscanf(chars[i], "%04hX#%02hhX#%04hX#%s", &chr->handle,
624 &chr->perm, &chr->end, chr->type);
625 if (ret < 4) {
626 g_free(chr);
627 continue;
628 }
629
630 chr->prim = prim;
631 chr->path = g_strdup_printf("%s/characteristic%04x",
632 prim->path, chr->handle);
633
634 l = g_slist_append(l, chr);
635 }
636
637 g_strfreev(chars);
638
639 return l;
640 }
641
load_characteristics(gpointer data,gpointer user_data)642 static void load_characteristics(gpointer data, gpointer user_data)
643 {
644 struct primary *prim = data;
645 struct att_primary *att = prim->att;
646 struct gatt_service *gatt = user_data;
647 GSList *chrs_list;
648 char *str;
649
650 if (prim->chars) {
651 DBG("Characteristics already loaded");
652 return;
653 }
654
655 str = read_device_characteristics(&gatt->sba, &gatt->dba, att->start);
656 if (str == NULL)
657 return;
658
659 chrs_list = string_to_characteristic_list(prim, str);
660
661 free(str);
662
663 if (chrs_list == NULL)
664 return;
665
666 prim->chars = chrs_list;
667 register_characteristics(prim);
668
669 return;
670 }
671
store_attribute(struct gatt_service * gatt,uint16_t handle,uint16_t type,uint8_t * value,gsize len)672 static void store_attribute(struct gatt_service *gatt, uint16_t handle,
673 uint16_t type, uint8_t *value, gsize len)
674 {
675 bt_uuid_t uuid;
676 char *str, *tmp;
677 guint i;
678
679 str = g_malloc0(MAX_LEN_UUID_STR + len * 2 + 1);
680
681 bt_uuid16_create(&uuid, type);
682 bt_uuid_to_string(&uuid, str, MAX_LEN_UUID_STR);
683
684 str[MAX_LEN_UUID_STR - 1] = '#';
685
686 for (i = 0, tmp = str + MAX_LEN_UUID_STR; i < len; i++, tmp += 2)
687 sprintf(tmp, "%02X", value[i]);
688
689 write_device_attribute(&gatt->sba, &gatt->dba, handle, str);
690 g_free(str);
691 }
692
update_char_desc(guint8 status,const guint8 * pdu,guint16 len,gpointer user_data)693 static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
694 gpointer user_data)
695 {
696 struct query_data *current = user_data;
697 struct gatt_service *gatt = current->prim->gatt;
698 struct characteristic *chr = current->chr;
699
700 if (status == 0) {
701
702 g_free(chr->desc);
703
704 chr->desc = g_malloc(len);
705 memcpy(chr->desc, pdu + 1, len - 1);
706 chr->desc[len - 1] = '\0';
707
708 store_attribute(gatt, current->handle,
709 GATT_CHARAC_USER_DESC_UUID,
710 (void *) chr->desc, len);
711 } else if (status == ATT_ECODE_INSUFF_ENC) {
712 GIOChannel *io = g_attrib_get_channel(gatt->attrib);
713
714 if (bt_io_set(io, BT_IO_L2CAP, NULL,
715 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
716 BT_IO_OPT_INVALID)) {
717 gatt_read_char(gatt->attrib, current->handle, 0,
718 update_char_desc, current);
719 return;
720 }
721 }
722
723 g_attrib_unref(gatt->attrib);
724 g_free(current);
725 }
726
update_char_format(guint8 status,const guint8 * pdu,guint16 len,gpointer user_data)727 static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
728 gpointer user_data)
729 {
730 struct query_data *current = user_data;
731 struct gatt_service *gatt = current->prim->gatt;
732 struct characteristic *chr = current->chr;
733
734 if (status != 0)
735 goto done;
736
737 if (len < 8)
738 goto done;
739
740 g_free(chr->format);
741
742 chr->format = g_new0(struct format, 1);
743 memcpy(chr->format, pdu + 1, 7);
744
745 store_attribute(gatt, current->handle, GATT_CHARAC_FMT_UUID,
746 (void *) chr->format, sizeof(*chr->format));
747
748 done:
749 g_attrib_unref(gatt->attrib);
750 g_free(current);
751 }
752
update_char_value(guint8 status,const guint8 * pdu,guint16 len,gpointer user_data)753 static void update_char_value(guint8 status, const guint8 *pdu,
754 guint16 len, gpointer user_data)
755 {
756 struct query_data *current = user_data;
757 struct gatt_service *gatt = current->prim->gatt;
758 struct characteristic *chr = current->chr;
759
760 if (status == 0)
761 characteristic_set_value(chr, pdu + 1, len - 1);
762 else if (status == ATT_ECODE_INSUFF_ENC) {
763 GIOChannel *io = g_attrib_get_channel(gatt->attrib);
764
765 if (bt_io_set(io, BT_IO_L2CAP, NULL,
766 BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
767 BT_IO_OPT_INVALID)) {
768 gatt_read_char(gatt->attrib, chr->handle, 0,
769 update_char_value, current);
770 return;
771 }
772 }
773
774 g_attrib_unref(gatt->attrib);
775 g_free(current);
776 }
777
uuid_desc16_cmp(bt_uuid_t * uuid,guint16 desc)778 static int uuid_desc16_cmp(bt_uuid_t *uuid, guint16 desc)
779 {
780 bt_uuid_t u16;
781
782 bt_uuid16_create(&u16, desc);
783
784 return bt_uuid_cmp(uuid, &u16);
785 }
786
descriptor_cb(guint8 status,const guint8 * pdu,guint16 plen,gpointer user_data)787 static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
788 gpointer user_data)
789 {
790 struct query_data *current = user_data;
791 struct gatt_service *gatt = current->prim->gatt;
792 struct att_data_list *list;
793 guint8 format;
794 int i;
795
796 if (status != 0)
797 goto done;
798
799 DBG("Find Information Response received");
800
801 list = dec_find_info_resp(pdu, plen, &format);
802 if (list == NULL)
803 goto done;
804
805 for (i = 0; i < list->num; i++) {
806 guint16 handle;
807 bt_uuid_t uuid;
808 uint8_t *info = list->data[i];
809 struct query_data *qfmt;
810
811 handle = att_get_u16(info);
812
813 if (format == 0x01) {
814 uuid = att_get_uuid16(&info[2]);
815 } else {
816 /* Currently, only "user description" and "presentation
817 * format" descriptors are used, and both have 16-bit
818 * UUIDs. Therefore there is no need to support format
819 * 0x02 yet. */
820 continue;
821 }
822 qfmt = g_new0(struct query_data, 1);
823 qfmt->prim = current->prim;
824 qfmt->chr = current->chr;
825 qfmt->handle = handle;
826
827 if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0) {
828 gatt->attrib = g_attrib_ref(gatt->attrib);
829 gatt_read_char(gatt->attrib, handle, 0, update_char_desc,
830 qfmt);
831 } else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0) {
832 gatt->attrib = g_attrib_ref(gatt->attrib);
833 gatt_read_char(gatt->attrib, handle, 0,
834 update_char_format, qfmt);
835 } else
836 g_free(qfmt);
837 }
838
839 att_data_list_free(list);
840 done:
841 g_attrib_unref(gatt->attrib);
842 g_free(current);
843 }
844
update_all_chars(gpointer data,gpointer user_data)845 static void update_all_chars(gpointer data, gpointer user_data)
846 {
847 struct query_data *qdesc, *qvalue;
848 struct characteristic *chr = data;
849 struct primary *prim = user_data;
850 struct gatt_service *gatt = prim->gatt;
851
852 qdesc = g_new0(struct query_data, 1);
853 qdesc->prim = prim;
854 qdesc->chr = chr;
855
856 gatt->attrib = g_attrib_ref(gatt->attrib);
857 gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb,
858 qdesc);
859
860 qvalue = g_new0(struct query_data, 1);
861 qvalue->prim = prim;
862 qvalue->chr = chr;
863
864 gatt->attrib = g_attrib_ref(gatt->attrib);
865 gatt_read_char(gatt->attrib, chr->handle, 0, update_char_value, qvalue);
866 }
867
char_discovered_cb(GSList * characteristics,guint8 status,gpointer user_data)868 static void char_discovered_cb(GSList *characteristics, guint8 status,
869 gpointer user_data)
870 {
871 DBusMessage *reply;
872 DBusMessageIter iter, array_iter;
873 struct query_data *current = user_data;
874 struct primary *prim = current->prim;
875 struct att_primary *att = prim->att;
876 struct gatt_service *gatt = prim->gatt;
877 uint16_t *previous_end = NULL;
878 GSList *l;
879
880 if (status != 0) {
881 const char *str = att_ecode2str(status);
882
883 DBG("Discover all characteristics failed: %s", str);
884 reply = btd_error_failed(current->msg, str);
885 goto fail;
886 }
887
888 for (l = characteristics; l; l = l->next) {
889 struct att_char *current_chr = l->data;
890 struct characteristic *chr;
891 guint handle = current_chr->value_handle;
892 GSList *lchr;
893
894 lchr = g_slist_find_custom(prim->chars,
895 GUINT_TO_POINTER(handle), characteristic_handle_cmp);
896 if (lchr)
897 continue;
898
899 chr = g_new0(struct characteristic, 1);
900 chr->prim = prim;
901 chr->perm = current_chr->properties;
902 chr->handle = current_chr->value_handle;
903 chr->path = g_strdup_printf("%s/characteristic%04x",
904 prim->path, chr->handle);
905 strncpy(chr->type, current_chr->uuid, sizeof(chr->type));
906
907 if (previous_end)
908 *previous_end = current_chr->handle;
909
910 previous_end = &chr->end;
911
912 prim->chars = g_slist_append(prim->chars, chr);
913 }
914
915 if (previous_end)
916 *previous_end = att->end;
917
918 store_characteristics(gatt, prim);
919 register_characteristics(prim);
920
921 reply = dbus_message_new_method_return(current->msg);
922
923 dbus_message_iter_init_append(reply, &iter);
924
925 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
926 DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
927
928 for (l = prim->chars; l; l = l->next) {
929 struct characteristic *chr = l->data;
930
931 dbus_message_iter_append_basic(&array_iter,
932 DBUS_TYPE_OBJECT_PATH, &chr->path);
933 }
934
935 dbus_message_iter_close_container(&iter, &array_iter);
936
937 g_slist_foreach(prim->chars, update_all_chars, prim);
938
939 fail:
940 g_dbus_send_message(gatt->conn, reply);
941 g_attrib_unref(gatt->attrib);
942 g_free(current);
943 }
944
discover_char(DBusConnection * conn,DBusMessage * msg,void * data)945 static DBusMessage *discover_char(DBusConnection *conn, DBusMessage *msg,
946 void *data)
947 {
948 struct primary *prim = data;
949 struct att_primary *att = prim->att;
950 struct gatt_service *gatt = prim->gatt;
951 struct query_data *qchr;
952 GError *gerr = NULL;
953
954 if (l2cap_connect(prim->gatt, &gerr, FALSE) < 0) {
955 DBusMessage *reply = btd_error_failed(msg, gerr->message);
956 g_error_free(gerr);
957 return reply;
958 }
959
960 qchr = g_new0(struct query_data, 1);
961 qchr->prim = prim;
962 qchr->msg = dbus_message_ref(msg);
963
964 gatt_discover_char(gatt->attrib, att->start, att->end, NULL,
965 char_discovered_cb, qchr);
966
967 return NULL;
968 }
969
prim_get_properties(DBusConnection * conn,DBusMessage * msg,void * data)970 static DBusMessage *prim_get_properties(DBusConnection *conn, DBusMessage *msg,
971 void *data)
972 {
973 struct primary *prim = data;
974 DBusMessage *reply;
975 DBusMessageIter iter;
976 DBusMessageIter dict;
977 GSList *l;
978 char **chars;
979 const char *uuid;
980 int i;
981
982 reply = dbus_message_new_method_return(msg);
983 if (!reply)
984 return NULL;
985
986 dbus_message_iter_init_append(reply, &iter);
987
988 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
989 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
990 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
991 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
992
993 chars = g_new0(char *, g_slist_length(prim->chars) + 1);
994
995 for (i = 0, l = prim->chars; l; l = l->next, i++) {
996 struct characteristic *chr = l->data;
997 chars[i] = chr->path;
998 }
999
1000 dict_append_array(&dict, "Characteristics", DBUS_TYPE_OBJECT_PATH,
1001 &chars, i);
1002 uuid = prim->att->uuid;
1003 dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
1004
1005 g_free(chars);
1006
1007 dbus_message_iter_close_container(&iter, &dict);
1008
1009 return reply;
1010 }
1011
1012 static GDBusMethodTable prim_methods[] = {
1013 { "DiscoverCharacteristics", "", "ao", discover_char,
1014 G_DBUS_METHOD_FLAG_ASYNC },
1015 { "RegisterCharacteristicsWatcher", "o", "",
1016 register_watcher },
1017 { "UnregisterCharacteristicsWatcher", "o", "",
1018 unregister_watcher },
1019 { "GetProperties", "", "a{sv}",prim_get_properties },
1020 { }
1021 };
1022
register_primaries(struct gatt_service * gatt,GSList * primaries)1023 static GSList *register_primaries(struct gatt_service *gatt, GSList *primaries)
1024 {
1025 GSList *l, *paths;
1026
1027 for (paths = NULL, l = primaries; l; l = l->next) {
1028 struct att_primary *att = l->data;
1029 struct primary *prim;
1030
1031 prim = g_new0(struct primary, 1);
1032 prim->att = att;
1033 prim->gatt = gatt;
1034 prim->path = g_strdup_printf("%s/service%04x", gatt->path,
1035 att->start);
1036
1037 g_dbus_register_interface(gatt->conn, prim->path,
1038 CHAR_INTERFACE, prim_methods,
1039 NULL, NULL, prim, NULL);
1040 DBG("Registered: %s", prim->path);
1041
1042 gatt->primary = g_slist_append(gatt->primary, prim);
1043 paths = g_slist_append(paths, g_strdup(prim->path));
1044 load_characteristics(prim, gatt);
1045 }
1046
1047 return paths;
1048 }
1049
attrib_client_register(DBusConnection * connection,struct btd_device * device,int psm,GAttrib * attrib,GSList * primaries)1050 GSList *attrib_client_register(DBusConnection *connection,
1051 struct btd_device *device, int psm,
1052 GAttrib *attrib, GSList *primaries)
1053 {
1054 struct btd_adapter *adapter = device_get_adapter(device);
1055 const char *path = device_get_path(device);
1056 struct gatt_service *gatt;
1057 bdaddr_t sba, dba;
1058
1059 adapter_get_address(adapter, &sba);
1060 device_get_address(device, &dba);
1061
1062 gatt = g_new0(struct gatt_service, 1);
1063 gatt->dev = btd_device_ref(device);
1064 gatt->conn = dbus_connection_ref(connection);
1065 gatt->listen = FALSE;
1066 gatt->path = g_strdup(path);
1067 bacpy(&gatt->sba, &sba);
1068 bacpy(&gatt->dba, &dba);
1069 gatt->psm = psm;
1070
1071 if (attrib)
1072 gatt->attrib = g_attrib_ref(attrib);
1073
1074 gatt_services = g_slist_append(gatt_services, gatt);
1075
1076 return register_primaries(gatt, primaries);
1077 }
1078
attrib_client_unregister(struct btd_device * device)1079 void attrib_client_unregister(struct btd_device *device)
1080 {
1081 struct gatt_service *gatt;
1082 GSList *l, *lp, *lc;
1083
1084 l = g_slist_find_custom(gatt_services, device, gatt_dev_cmp);
1085 if (!l)
1086 return;
1087
1088 gatt = l->data;
1089 gatt_services = g_slist_remove(gatt_services, gatt);
1090
1091 for (lp = gatt->primary; lp; lp = lp->next) {
1092 struct primary *prim = lp->data;
1093 for (lc = prim->chars; lc; lc = lc->next) {
1094 struct characteristic *chr = lc->data;
1095 g_dbus_unregister_interface(gatt->conn, chr->path,
1096 CHAR_INTERFACE);
1097 }
1098 g_dbus_unregister_interface(gatt->conn, prim->path,
1099 CHAR_INTERFACE);
1100 }
1101
1102 gatt_service_free(gatt);
1103 }
1104