3
* BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2010 Nokia Corporation
6
* Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
34
#include <bluetooth/bluetooth.h>
35
#include <bluetooth/sdp.h>
36
#include <bluetooth/sdp_lib.h>
43
#include "glib-helper.h"
44
#include "dbus-common.h"
53
#define CHAR_INTERFACE "org.bluez.Characteristic"
56
struct btd_device *dev;
73
} __attribute__ ((packed));
76
struct gatt_service *gatt;
85
struct characteristic {
94
struct format *format;
100
struct primary *prim;
101
struct characteristic *chr;
109
struct primary *prim;
112
static GSList *gatt_services = NULL;
114
static DBusConnection *connection;
116
static void characteristic_free(void *user_data)
118
struct characteristic *chr = user_data;
128
static void watcher_free(void *user_data)
130
struct watcher *watcher = user_data;
132
g_free(watcher->path);
133
g_free(watcher->name);
137
static void primary_free(void *user_data)
139
struct primary *prim = user_data;
142
for (l = prim->watchers; l; l = l->next) {
143
struct watcher *watcher = l->data;
144
g_dbus_remove_watch(connection, watcher->id);
147
g_slist_foreach(prim->chars, (GFunc) characteristic_free, NULL);
148
g_slist_free(prim->chars);
153
static void gatt_service_free(void *user_data)
155
struct gatt_service *gatt = user_data;
157
g_slist_foreach(gatt->primary, (GFunc) primary_free, NULL);
158
g_slist_free(gatt->primary);
159
g_attrib_unref(gatt->attrib);
161
btd_device_unref(gatt->dev);
165
static int gatt_dev_cmp(gconstpointer a, gconstpointer b)
167
const struct gatt_service *gatt = a;
168
const struct btd_device *dev = b;
170
return gatt->dev == dev;
173
static int characteristic_handle_cmp(gconstpointer a, gconstpointer b)
175
const struct characteristic *chr = a;
176
uint16_t handle = GPOINTER_TO_UINT(b);
178
return chr->handle - handle;
181
static int watcher_cmp(gconstpointer a, gconstpointer b)
183
const struct watcher *watcher = a;
184
const struct watcher *match = b;
187
ret = g_strcmp0(watcher->name, match->name);
191
return g_strcmp0(watcher->path, match->path);
194
static inline DBusMessage *invalid_args(DBusMessage *msg)
196
return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
197
"Invalid arguments in method call");
200
static inline DBusMessage *not_authorized(DBusMessage *msg)
202
return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized",
206
static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
208
DBusMessageIter dict;
209
const char *name = "";
212
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
213
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
214
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
215
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
217
uuid = bt_uuid2string(&chr->type);
218
dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
221
/* FIXME: Translate UUID to name. */
222
dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &name);
225
dict_append_entry(&dict, "Description", DBUS_TYPE_STRING,
229
dict_append_array(&dict, "Value", DBUS_TYPE_BYTE, &chr->value,
232
/* FIXME: Missing Format, Value and Representation */
234
dbus_message_iter_close_container(iter, &dict);
237
static void watcher_exit(DBusConnection *conn, void *user_data)
239
struct watcher *watcher = user_data;
240
struct primary *prim = watcher->prim;
241
struct gatt_service *gatt = prim->gatt;
243
DBG("%s watcher %s exited", prim->path, watcher->name);
245
prim->watchers = g_slist_remove(prim->watchers, watcher);
247
g_attrib_unref(gatt->attrib);
250
static int characteristic_set_value(struct characteristic *chr,
251
const uint8_t *value, size_t vlen)
253
chr->value = g_try_realloc(chr->value, vlen);
254
if (chr->value == NULL)
257
memcpy(chr->value, value, vlen);
263
static void update_watchers(gpointer data, gpointer user_data)
265
struct watcher *w = data;
266
struct characteristic *chr = user_data;
269
msg = dbus_message_new_method_call(w->name, w->path,
270
"org.bluez.Watcher", "ValueChanged");
274
dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &chr->path,
275
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
276
&chr->value, chr->vlen, DBUS_TYPE_INVALID);
278
dbus_message_set_no_reply(msg, TRUE);
279
g_dbus_send_message(connection, msg);
282
static void events_handler(const uint8_t *pdu, uint16_t len,
285
struct gatt_service *gatt = user_data;
286
struct characteristic *chr;
287
struct primary *prim;
288
GSList *lprim, *lchr;
289
uint8_t opdu[ATT_MAX_MTU];
290
guint handle = att_get_u16(&pdu[1]);
293
for (lprim = gatt->primary, prim = NULL, chr = NULL; lprim;
294
lprim = lprim->next) {
297
lchr = g_slist_find_custom(prim->chars,
298
GUINT_TO_POINTER(handle), characteristic_handle_cmp);
306
DBG("Attribute handle 0x%02x not found", handle);
311
case ATT_OP_HANDLE_IND:
312
olen = enc_confirmation(opdu, sizeof(opdu));
313
g_attrib_send(gatt->attrib, opdu[0], opdu, olen,
315
case ATT_OP_HANDLE_NOTIFY:
316
if (characteristic_set_value(chr, &pdu[3], len - 3) < 0)
317
DBG("Can't change Characteristic %0x02x", handle);
319
g_slist_foreach(prim->watchers, update_watchers, chr);
324
static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
327
static void attrib_destroy(gpointer user_data)
329
struct gatt_service *gatt = user_data;
334
static void attrib_disconnect(gpointer user_data)
336
struct gatt_service *gatt = user_data;
338
/* Remote initiated disconnection only */
339
g_attrib_unref(gatt->attrib);
342
static void connect_cb(GIOChannel *chan, GError *gerr, gpointer user_data)
344
struct gatt_service *gatt = user_data;
348
error("%s", gerr->message);
352
if (gatt->attrib == NULL)
355
/* Listen mode: used for notification and indication */
356
if (gatt->listen == TRUE) {
357
g_attrib_register(gatt->attrib,
358
ATT_OP_HANDLE_NOTIFY,
359
events_handler, gatt, NULL);
360
g_attrib_register(gatt->attrib,
362
events_handler, gatt, NULL);
366
atid = gatt_discover_primary(gatt->attrib, 0x0001, 0xffff, NULL,
375
g_attrib_unref(gatt->attrib);
378
static DBusMessage *get_characteristics(DBusConnection *conn,
379
DBusMessage *msg, void *data)
381
struct primary *prim = data;
383
DBusMessageIter iter, array;
386
reply = dbus_message_new_method_return(msg);
390
dbus_message_iter_init_append(reply, &iter);
392
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
393
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
394
DBUS_TYPE_OBJECT_PATH_AS_STRING
395
DBUS_TYPE_ARRAY_AS_STRING
396
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
397
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
398
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
399
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
401
for (l = prim->chars; l; l = l->next) {
402
struct characteristic *chr = l->data;
405
DBG("path %s", chr->path);
407
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY,
410
dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH,
413
append_char_dict(&sub, chr);
415
dbus_message_iter_close_container(&array, &sub);
418
dbus_message_iter_close_container(&iter, &array);
423
static int l2cap_connect(struct gatt_service *gatt, GError **gerr,
428
if (gatt->attrib != NULL) {
429
gatt->attrib = g_attrib_ref(gatt->attrib);
434
* FIXME: If the service doesn't support Client Characteristic
435
* Configuration it is necessary to poll the server from time
436
* to time checking for modifications.
438
io = bt_io_connect(BT_IO_L2CAP, connect_cb, gatt, NULL, gerr,
439
BT_IO_OPT_SOURCE_BDADDR, &gatt->sba,
440
BT_IO_OPT_DEST_BDADDR, &gatt->dba,
441
BT_IO_OPT_PSM, gatt->psm,
442
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
447
gatt->attrib = g_attrib_new(io);
448
g_io_channel_unref(io);
449
gatt->listen = listen;
451
g_attrib_set_destroy_function(gatt->attrib, attrib_destroy, gatt);
452
g_attrib_set_disconnect_function(gatt->attrib, attrib_disconnect,
458
static DBusMessage *register_watcher(DBusConnection *conn,
459
DBusMessage *msg, void *data)
461
const char *sender = dbus_message_get_sender(msg);
462
struct primary *prim = data;
463
struct watcher *watcher;
467
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
469
return invalid_args(msg);
471
if (l2cap_connect(prim->gatt, &gerr, TRUE) < 0) {
473
reply = g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
474
"%s", gerr->message);
480
watcher = g_new0(struct watcher, 1);
481
watcher->name = g_strdup(sender);
482
watcher->prim = prim;
483
watcher->path = g_strdup(path);
484
watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
485
watcher, watcher_free);
487
prim->watchers = g_slist_append(prim->watchers, watcher);
489
return dbus_message_new_method_return(msg);
492
static DBusMessage *unregister_watcher(DBusConnection *conn,
493
DBusMessage *msg, void *data)
495
const char *sender = dbus_message_get_sender(msg);
496
struct primary *prim = data;
497
struct watcher *watcher, *match;
501
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
503
return invalid_args(msg);
505
match = g_new0(struct watcher, 1);
506
match->name = g_strdup(sender);
507
match->path = g_strdup(path);
508
l = g_slist_find_custom(prim->watchers, match, watcher_cmp);
511
return not_authorized(msg);
514
g_dbus_remove_watch(conn, watcher->id);
515
prim->watchers = g_slist_remove(prim->watchers, watcher);
516
watcher_free(watcher);
518
return dbus_message_new_method_return(msg);
521
static GDBusMethodTable prim_methods[] = {
522
{ "GetCharacteristics", "", "a{oa{sv}}", get_characteristics},
523
{ "RegisterCharacteristicsWatcher", "o", "",
525
{ "UnregisterCharacteristicsWatcher", "o", "",
526
unregister_watcher },
530
static DBusMessage *set_value(DBusConnection *conn, DBusMessage *msg,
531
DBusMessageIter *iter, struct characteristic *chr)
533
struct gatt_service *gatt = chr->prim->gatt;
539
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
540
dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
541
return invalid_args(msg);
543
dbus_message_iter_recurse(iter, &sub);
545
dbus_message_iter_get_fixed_array(&sub, &value, &len);
547
if (l2cap_connect(gatt, &gerr, FALSE) < 0) {
549
reply = g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
550
"%s", gerr->message);
556
gatt_write_cmd(gatt->attrib, chr->handle, value, len, NULL, NULL);
558
characteristic_set_value(chr, value, len);
560
return dbus_message_new_method_return(msg);
563
static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
566
struct characteristic *chr = data;
568
DBusMessageIter iter;
570
reply = dbus_message_new_method_return(msg);
574
dbus_message_iter_init_append(reply, &iter);
576
append_char_dict(&iter, chr);
581
static DBusMessage *set_property(DBusConnection *conn,
582
DBusMessage *msg, void *data)
584
struct characteristic *chr = data;
585
DBusMessageIter iter;
587
const char *property;
589
if (!dbus_message_iter_init(msg, &iter))
590
return invalid_args(msg);
592
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
593
return invalid_args(msg);
595
dbus_message_iter_get_basic(&iter, &property);
596
dbus_message_iter_next(&iter);
598
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
599
return invalid_args(msg);
601
dbus_message_iter_recurse(&iter, &sub);
603
if (g_str_equal("Value", property))
604
return set_value(conn, msg, &sub, chr);
606
return invalid_args(msg);
609
static GDBusMethodTable char_methods[] = {
610
{ "GetProperties", "", "a{sv}", get_properties },
611
{ "SetProperty", "sv", "", set_property,
612
G_DBUS_METHOD_FLAG_ASYNC},
616
static void register_primary(struct gatt_service *gatt)
620
for (l = gatt->primary; l; l = l->next) {
621
struct primary *prim = l->data;
622
g_dbus_register_interface(connection, prim->path,
623
CHAR_INTERFACE, prim_methods,
624
NULL, NULL, prim, NULL);
625
DBG("Registered: %s", prim->path);
627
device_add_service(gatt->dev, prim->path);
631
static char *characteristic_list_to_string(GSList *chars)
633
GString *characteristics;
636
characteristics = g_string_new(NULL);
638
for (l = chars; l; l = l->next) {
639
struct characteristic *chr = l->data;
642
char uuidstr[MAX_LEN_UUID_STR];
644
memset(chr_str, 0, sizeof(chr_str));
646
uuid128 = sdp_uuid_to_uuid128(&chr->type);
647
sdp_uuid2strn(uuid128, uuidstr, MAX_LEN_UUID_STR);
651
snprintf(chr_str, sizeof(chr_str), "%04X#%02X#%04X#%s ",
652
chr->handle, chr->perm, chr->end, uuidstr);
654
characteristics = g_string_append(characteristics, chr_str);
657
return g_string_free(characteristics, FALSE);
660
static void store_characteristics(struct gatt_service *gatt,
661
struct primary *prim)
663
char *characteristics;
665
characteristics = characteristic_list_to_string(prim->chars);
667
write_device_characteristics(&gatt->sba, &gatt->dba, prim->start,
670
g_free(characteristics);
673
static void register_characteristics(struct primary *prim)
677
for (lc = prim->chars; lc; lc = lc->next) {
678
struct characteristic *chr = lc->data;
679
g_dbus_register_interface(connection, chr->path,
680
CHAR_INTERFACE, char_methods,
681
NULL, NULL, chr, NULL);
682
DBG("Registered: %s", chr->path);
686
static GSList *string_to_characteristic_list(struct primary *prim,
696
chars = g_strsplit(str, " ", 0);
700
for (i = 0; chars[i]; i++) {
701
struct characteristic *chr;
702
char uuidstr[MAX_LEN_UUID_STR + 1];
705
chr = g_new0(struct characteristic, 1);
707
ret = sscanf(chars[i], "%04hX#%02hhX#%04hX#%s", &chr->handle,
708
&chr->perm, &chr->end, uuidstr);
715
chr->path = g_strdup_printf("%s/characteristic%04x",
716
prim->path, chr->handle);
718
bt_string2uuid(&chr->type, uuidstr);
720
l = g_slist_append(l, chr);
728
static void load_characteristics(gpointer data, gpointer user_data)
730
struct primary *prim = data;
731
struct gatt_service *gatt = user_data;
736
DBG("Characteristics already loaded");
740
str = read_device_characteristics(&gatt->sba, &gatt->dba, prim->start);
744
chrs_list = string_to_characteristic_list(prim, str);
748
if (chrs_list == NULL)
751
prim->chars = chrs_list;
752
register_characteristics(prim);
757
static void store_attribute(struct gatt_service *gatt, uint16_t handle,
758
uint16_t type, uint8_t *value, gsize len)
761
char *str, *uuidstr, *tmp;
764
str = g_malloc0(MAX_LEN_UUID_STR + len * 2 + 1);
766
sdp_uuid16_create(&uuid, type);
767
uuidstr = bt_uuid2string(&uuid);
768
strcpy(str, uuidstr);
771
str[MAX_LEN_UUID_STR - 1] = '#';
773
for (i = 0, tmp = str + MAX_LEN_UUID_STR; i < len; i++, tmp += 2)
774
sprintf(tmp, "%02X", value[i]);
776
write_device_attribute(&gatt->sba, &gatt->dba, handle, str);
780
static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
783
struct query_data *current = user_data;
784
struct gatt_service *gatt = current->prim->gatt;
785
struct characteristic *chr = current->chr;
792
chr->desc = g_malloc(len);
793
memcpy(chr->desc, pdu + 1, len - 1);
794
chr->desc[len - 1] = '\0';
796
store_attribute(gatt, current->handle, GATT_CHARAC_USER_DESC_UUID,
797
(void *) chr->desc, len);
799
g_attrib_unref(gatt->attrib);
803
static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
806
struct query_data *current = user_data;
807
struct gatt_service *gatt = current->prim->gatt;
808
struct characteristic *chr = current->chr;
818
chr->format = g_new0(struct format, 1);
819
memcpy(chr->format, pdu + 1, 7);
821
store_attribute(gatt, current->handle, GATT_CHARAC_FMT_UUID,
822
(void *) chr->format, sizeof(*chr->format));
825
g_attrib_unref(gatt->attrib);
829
static void update_char_value(guint8 status, const guint8 *pdu,
830
guint16 len, gpointer user_data)
832
struct query_data *current = user_data;
833
struct gatt_service *gatt = current->prim->gatt;
834
struct characteristic *chr = current->chr;
837
characteristic_set_value(chr, pdu + 1, len - 1);
839
g_attrib_unref(gatt->attrib);
843
static int uuid_desc16_cmp(uuid_t *uuid, guint16 desc)
847
sdp_uuid16_create(&u16, desc);
849
return sdp_uuid_cmp(uuid, &u16);
852
static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
855
struct query_data *current = user_data;
856
struct gatt_service *gatt = current->prim->gatt;
857
struct att_data_list *list;
864
DBG("Find Information Response received");
866
list = dec_find_info_resp(pdu, plen, &format);
870
for (i = 0; i < list->num; i++) {
873
uint8_t *info = list->data[i];
874
struct query_data *qfmt;
876
handle = att_get_u16(info);
878
if (format == 0x01) {
879
sdp_uuid16_create(&uuid, att_get_u16(&info[2]));
881
/* Currently, only "user description" and "presentation
882
* format" descriptors are used, and both have 16-bit
883
* UUIDs. Therefore there is no need to support format
887
qfmt = g_new0(struct query_data, 1);
888
qfmt->prim = current->prim;
889
qfmt->chr = current->chr;
890
qfmt->handle = handle;
892
if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0) {
893
gatt->attrib = g_attrib_ref(gatt->attrib);
894
gatt_read_char(gatt->attrib, handle, update_char_desc,
896
} else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0) {
897
gatt->attrib = g_attrib_ref(gatt->attrib);
898
gatt_read_char(gatt->attrib, handle,
899
update_char_format, qfmt);
904
att_data_list_free(list);
906
g_attrib_unref(gatt->attrib);
910
static void update_all_chars(gpointer data, gpointer user_data)
912
struct query_data *qdesc, *qvalue;
913
struct characteristic *chr = data;
914
struct primary *prim = user_data;
915
struct gatt_service *gatt = prim->gatt;
917
qdesc = g_new0(struct query_data, 1);
921
gatt->attrib = g_attrib_ref(gatt->attrib);
922
gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb,
925
qvalue = g_new0(struct query_data, 1);
929
gatt->attrib = g_attrib_ref(gatt->attrib);
930
gatt_read_char(gatt->attrib, chr->handle, update_char_value, qvalue);
933
static void char_discovered_cb(guint8 status, const guint8 *pdu, guint16 plen,
936
struct query_data *current = user_data;
937
struct primary *prim = current->prim;
938
struct gatt_service *gatt = prim->gatt;
939
struct att_data_list *list;
940
uint16_t last, *previous_end = NULL;
943
if (status == ATT_ECODE_ATTR_NOT_FOUND)
947
DBG("Discover all characteristics failed: %s",
948
att_ecode2str(status));
953
DBG("Read by Type Response received");
955
list = dec_read_by_type_resp(pdu, plen);
959
for (i = 0, last = 0; i < list->num; i++) {
960
uint8_t *decl = list->data[i];
961
struct characteristic *chr;
963
chr = g_new0(struct characteristic, 1);
966
chr->handle = att_get_u16(&decl[3]);
967
chr->path = g_strdup_printf("%s/characteristic%04x",
968
prim->path, chr->handle);
969
if (list->len == 7) {
970
sdp_uuid16_create(&chr->type,
971
att_get_u16(&decl[5]));
973
sdp_uuid128_create(&chr->type, &decl[5]);
976
*previous_end = att_get_u16(decl);
980
previous_end = &chr->end;
982
prim->chars = g_slist_append(prim->chars, chr);
986
*previous_end = prim->end;
988
att_data_list_free(list);
990
if (last >= prim->end)
993
/* Fetch remaining characteristics for the CURRENT primary service */
994
gatt_discover_char(gatt->attrib, last + 1, prim->end,
995
char_discovered_cb, current);
1000
store_characteristics(gatt, prim);
1001
register_characteristics(prim);
1003
g_slist_foreach(prim->chars, update_all_chars, prim);
1006
g_attrib_unref(gatt->attrib);
1010
static void *attr_data_from_string(const char *str)
1016
size = strlen(str) / 2;
1017
data = g_try_malloc0(size);
1022
for (i = 0; i < size; i++) {
1023
memcpy(tmp, str + (i * 2), 2);
1024
data[i] = (uint8_t) strtol(tmp, NULL, 16);
1030
static int find_primary(gconstpointer a, gconstpointer b)
1032
const struct primary *primary = a;
1033
uint16_t handle = GPOINTER_TO_UINT(b);
1035
if (handle < primary->start)
1038
if (handle > primary->end)
1044
static int find_characteristic(gconstpointer a, gconstpointer b)
1046
const struct characteristic *chr = a;
1047
uint16_t handle = GPOINTER_TO_UINT(b);
1049
if (handle < chr->handle)
1052
if (handle > chr->end)
1058
static void load_attribute_data(char *key, char *value, void *data)
1060
struct gatt_service *gatt = data;
1061
struct characteristic *chr;
1062
struct primary *primary;
1063
char addr[18], dst[18];
1069
if (sscanf(key, "%17s#%04hX", addr, &handle) < 2)
1072
ba2str(&gatt->dba, dst);
1074
if (strcmp(addr, dst) != 0)
1079
l = g_slist_find_custom(gatt->primary, GUINT_TO_POINTER(h),
1086
l = g_slist_find_custom(primary->chars, GUINT_TO_POINTER(h),
1087
find_characteristic);
1093
/* value[] contains "<UUID>#<data>", but bt_string2uuid() expects a
1094
* string containing only the UUID. To avoid creating a new buffer,
1095
* "truncate" the string in place before calling bt_string2uuid(). */
1096
value[MAX_LEN_UUID_STR - 1] = '\0';
1097
if (bt_string2uuid(&uuid, value) < 0)
1100
/* Fill the characteristic field according to the attribute type. */
1101
if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0)
1102
chr->desc = attr_data_from_string(value + MAX_LEN_UUID_STR);
1103
else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0)
1104
chr->format = attr_data_from_string(value + MAX_LEN_UUID_STR);
1107
static char *primary_list_to_string(GSList *primary_list)
1112
services = g_string_new(NULL);
1114
for (l = primary_list; l; l = l->next) {
1115
struct primary *primary = l->data;
1118
char uuidstr[MAX_LEN_UUID_STR];
1120
memset(service, 0, sizeof(service));
1122
uuid128 = sdp_uuid_to_uuid128(&primary->uuid);
1123
sdp_uuid2strn(uuid128, uuidstr, MAX_LEN_UUID_STR);
1127
snprintf(service, sizeof(service), "%04X#%04X#%s ",
1128
primary->start, primary->end, uuidstr);
1130
services = g_string_append(services, service);
1133
return g_string_free(services, FALSE);
1136
static GSList *string_to_primary_list(struct gatt_service *gatt,
1146
services = g_strsplit(str, " ", 0);
1147
if (services == NULL)
1150
for (i = 0; services[i]; i++) {
1151
struct primary *prim;
1152
char uuidstr[MAX_LEN_UUID_STR + 1];
1155
prim = g_new0(struct primary, 1);
1158
ret = sscanf(services[i], "%04hX#%04hX#%s", &prim->start,
1159
&prim->end, uuidstr);
1166
prim->path = g_strdup_printf("%s/service%04x", gatt->path,
1169
bt_string2uuid(&prim->uuid, uuidstr);
1171
l = g_slist_append(l, prim);
1174
g_strfreev(services);
1179
static void store_primary_services(struct gatt_service *gatt)
1183
services = primary_list_to_string(gatt->primary);
1185
write_device_services(&gatt->sba, &gatt->dba, services);
1190
static gboolean load_primary_services(struct gatt_service *gatt)
1192
GSList *primary_list;
1195
if (gatt->primary) {
1196
DBG("Services already loaded");
1200
str = read_device_services(&gatt->sba, &gatt->dba);
1204
primary_list = string_to_primary_list(gatt, str);
1208
if (primary_list == NULL)
1211
gatt->primary = primary_list;
1212
register_primary(gatt);
1214
g_slist_foreach(gatt->primary, load_characteristics, gatt);
1215
read_device_attributes(&gatt->sba, load_attribute_data, gatt);
1220
static void discover_all_char(gpointer data, gpointer user_data)
1222
struct query_data *qchr;
1223
struct gatt_service *gatt = user_data;
1224
struct primary *prim = data;
1226
qchr = g_new0(struct query_data, 1);
1229
gatt->attrib = g_attrib_ref(gatt->attrib);
1230
gatt_discover_char(gatt->attrib, prim->start, prim->end,
1231
char_discovered_cb, qchr);
1234
static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
1237
struct gatt_service *gatt = user_data;
1238
struct att_data_list *list;
1240
uint16_t end, start;
1242
if (status == ATT_ECODE_ATTR_NOT_FOUND) {
1243
if (gatt->primary == NULL)
1246
store_primary_services(gatt);
1247
register_primary(gatt);
1249
g_slist_foreach(gatt->primary, discover_all_char, gatt);
1254
error("Discover all primary services failed: %s",
1255
att_ecode2str(status));
1259
list = dec_read_by_grp_resp(pdu, plen);
1261
error("Protocol error");
1265
DBG("Read by Group Type Response received");
1267
for (i = 0, end = 0; i < list->num; i++) {
1268
struct primary *prim;
1269
uint8_t *info = list->data[i];
1271
/* Each element contains: attribute handle, end group handle
1272
* and attribute value */
1273
start = att_get_u16(info);
1274
end = att_get_u16(&info[2]);
1276
prim = g_new0(struct primary, 1);
1278
prim->start = start;
1281
if (list->len == 6) {
1282
sdp_uuid16_create(&prim->uuid,
1283
att_get_u16(&info[4]));
1285
} else if (list->len == 20) {
1286
/* FIXME: endianness */
1287
sdp_uuid128_create(&prim->uuid, &info[4]);
1289
DBG("ATT: Invalid Length field");
1291
att_data_list_free(list);
1295
prim->path = g_strdup_printf("%s/service%04x", gatt->path,
1298
gatt->primary = g_slist_append(gatt->primary, prim);
1301
att_data_list_free(list);
1304
DBG("ATT: Invalid PDU format");
1309
* Discover all primary services sub-procedure shall send another
1310
* Read by Group Type Request until Error Response is received and
1311
* the Error Code is set to Attribute Not Found.
1313
gatt->attrib = g_attrib_ref(gatt->attrib);
1314
gatt->atid = gatt_discover_primary(gatt->attrib, end + 1, 0xffff, NULL,
1317
g_attrib_unref(gatt->attrib);
1320
int attrib_client_register(struct btd_device *device, int psm)
1322
struct btd_adapter *adapter = device_get_adapter(device);
1323
const char *path = device_get_path(device);
1324
struct gatt_service *gatt;
1327
adapter_get_address(adapter, &sba);
1328
device_get_address(device, &dba);
1330
gatt = g_new0(struct gatt_service, 1);
1331
gatt->dev = btd_device_ref(device);
1332
gatt->listen = FALSE;
1333
gatt->path = g_strdup(path);
1334
bacpy(&gatt->sba, &sba);
1335
bacpy(&gatt->dba, &dba);
1338
if (load_primary_services(gatt))
1339
DBG("Primary services loaded");
1341
gatt_services = g_slist_append(gatt_services, gatt);
1346
void attrib_client_unregister(struct btd_device *device)
1348
struct gatt_service *gatt;
1349
GSList *l, *lp, *lc;
1351
l = g_slist_find_custom(gatt_services, device, gatt_dev_cmp);
1356
gatt_services = g_slist_remove(gatt_services, gatt);
1358
for (lp = gatt->primary; lp; lp = lp->next) {
1359
struct primary *prim = lp->data;
1360
for (lc = prim->chars; lc; lc = lc->next) {
1361
struct characteristic *chr = lc->data;
1362
g_dbus_unregister_interface(connection, chr->path,
1365
g_dbus_unregister_interface(connection, prim->path,
1369
gatt_service_free(gatt);
1372
int attrib_client_init(DBusConnection *conn)
1375
connection = dbus_connection_ref(conn);
1378
* FIXME: if the adapter supports BLE start scanning. Temporary
1379
* solution, this approach doesn't allow to control scanning based
1380
* on the discoverable property.
1386
void attrib_client_exit(void)
1388
dbus_connection_unref(connection);