~ubuntu-branches/ubuntu/wily/bluez/wily

« back to all changes in this revision

Viewing changes to attrib/client.c

ImportĀ upstreamĀ versionĀ 4.81

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/sdp.h>
 
36
#include <bluetooth/sdp_lib.h>
 
37
 
 
38
#include "adapter.h"
 
39
#include "device.h"
 
40
#include "log.h"
 
41
#include "gdbus.h"
 
42
#include "error.h"
 
43
#include "glib-helper.h"
 
44
#include "dbus-common.h"
 
45
#include "btio.h"
 
46
#include "storage.h"
 
47
 
 
48
#include "att.h"
 
49
#include "gattrib.h"
 
50
#include "gatt.h"
 
51
#include "client.h"
 
52
 
 
53
#define CHAR_INTERFACE "org.bluez.Characteristic"
 
54
 
 
55
struct gatt_service {
 
56
        struct btd_device *dev;
 
57
        bdaddr_t sba;
 
58
        bdaddr_t dba;
 
59
        char *path;
 
60
        GSList *primary;
 
61
        GAttrib *attrib;
 
62
        int psm;
 
63
        guint atid;
 
64
        gboolean listen;
 
65
};
 
66
 
 
67
struct format {
 
68
        guint8 format;
 
69
        guint8 exponent;
 
70
        guint16 unit;
 
71
        guint8 namespace;
 
72
        guint16 desc;
 
73
} __attribute__ ((packed));
 
74
 
 
75
struct primary {
 
76
        struct gatt_service *gatt;
 
77
        char *path;
 
78
        uuid_t uuid;
 
79
        uint16_t start;
 
80
        uint16_t end;
 
81
        GSList *chars;
 
82
        GSList *watchers;
 
83
};
 
84
 
 
85
struct characteristic {
 
86
        struct primary *prim;
 
87
        char *path;
 
88
        uint16_t handle;
 
89
        uint16_t end;
 
90
        uint8_t perm;
 
91
        uuid_t type;
 
92
        char *name;
 
93
        char *desc;
 
94
        struct format *format;
 
95
        uint8_t *value;
 
96
        size_t vlen;
 
97
};
 
98
 
 
99
struct query_data {
 
100
        struct primary *prim;
 
101
        struct characteristic *chr;
 
102
        uint16_t handle;
 
103
};
 
104
 
 
105
struct watcher {
 
106
        guint id;
 
107
        char *name;
 
108
        char *path;
 
109
        struct primary *prim;
 
110
};
 
111
 
 
112
static GSList *gatt_services = NULL;
 
113
 
 
114
static DBusConnection *connection;
 
115
 
 
116
static void characteristic_free(void *user_data)
 
117
{
 
118
        struct characteristic *chr = user_data;
 
119
 
 
120
        g_free(chr->path);
 
121
        g_free(chr->desc);
 
122
        g_free(chr->format);
 
123
        g_free(chr->value);
 
124
        g_free(chr->name);
 
125
        g_free(chr);
 
126
}
 
127
 
 
128
static void watcher_free(void *user_data)
 
129
{
 
130
        struct watcher *watcher = user_data;
 
131
 
 
132
        g_free(watcher->path);
 
133
        g_free(watcher->name);
 
134
        g_free(watcher);
 
135
}
 
136
 
 
137
static void primary_free(void *user_data)
 
138
{
 
139
        struct primary *prim = user_data;
 
140
        GSList *l;
 
141
 
 
142
        for (l = prim->watchers; l; l = l->next) {
 
143
                struct watcher *watcher = l->data;
 
144
                g_dbus_remove_watch(connection, watcher->id);
 
145
        }
 
146
 
 
147
        g_slist_foreach(prim->chars, (GFunc) characteristic_free, NULL);
 
148
        g_slist_free(prim->chars);
 
149
        g_free(prim->path);
 
150
        g_free(prim);
 
151
}
 
152
 
 
153
static void gatt_service_free(void *user_data)
 
154
{
 
155
        struct gatt_service *gatt = user_data;
 
156
 
 
157
        g_slist_foreach(gatt->primary, (GFunc) primary_free, NULL);
 
158
        g_slist_free(gatt->primary);
 
159
        g_attrib_unref(gatt->attrib);
 
160
        g_free(gatt->path);
 
161
        btd_device_unref(gatt->dev);
 
162
        g_free(gatt);
 
163
}
 
164
 
 
165
static int gatt_dev_cmp(gconstpointer a, gconstpointer b)
 
166
{
 
167
        const struct gatt_service *gatt = a;
 
168
        const struct btd_device *dev = b;
 
169
 
 
170
        return gatt->dev == dev;
 
171
}
 
172
 
 
173
static int characteristic_handle_cmp(gconstpointer a, gconstpointer b)
 
174
{
 
175
        const struct characteristic *chr = a;
 
176
        uint16_t handle = GPOINTER_TO_UINT(b);
 
177
 
 
178
        return chr->handle - handle;
 
179
}
 
180
 
 
181
static int watcher_cmp(gconstpointer a, gconstpointer b)
 
182
{
 
183
        const struct watcher *watcher = a;
 
184
        const struct watcher *match = b;
 
185
        int ret;
 
186
 
 
187
        ret = g_strcmp0(watcher->name, match->name);
 
188
        if (ret != 0)
 
189
                return ret;
 
190
 
 
191
        return g_strcmp0(watcher->path, match->path);
 
192
}
 
193
 
 
194
static inline DBusMessage *invalid_args(DBusMessage *msg)
 
195
{
 
196
        return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
 
197
                        "Invalid arguments in method call");
 
198
}
 
199
 
 
200
static inline DBusMessage *not_authorized(DBusMessage *msg)
 
201
{
 
202
        return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized",
 
203
                        "Not authorized");
 
204
}
 
205
 
 
206
static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
 
207
{
 
208
        DBusMessageIter dict;
 
209
        const char *name = "";
 
210
        char *uuid;
 
211
 
 
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);
 
216
 
 
217
        uuid = bt_uuid2string(&chr->type);
 
218
        dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
 
219
        g_free(uuid);
 
220
 
 
221
        /* FIXME: Translate UUID to name. */
 
222
        dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &name);
 
223
 
 
224
        if (chr->desc)
 
225
                dict_append_entry(&dict, "Description", DBUS_TYPE_STRING,
 
226
                                                                &chr->desc);
 
227
 
 
228
        if (chr->value)
 
229
                dict_append_array(&dict, "Value", DBUS_TYPE_BYTE, &chr->value,
 
230
                                                                chr->vlen);
 
231
 
 
232
        /* FIXME: Missing Format, Value and Representation */
 
233
 
 
234
        dbus_message_iter_close_container(iter, &dict);
 
235
}
 
236
 
 
237
static void watcher_exit(DBusConnection *conn, void *user_data)
 
238
{
 
239
        struct watcher *watcher = user_data;
 
240
        struct primary *prim = watcher->prim;
 
241
        struct gatt_service *gatt = prim->gatt;
 
242
 
 
243
        DBG("%s watcher %s exited", prim->path, watcher->name);
 
244
 
 
245
        prim->watchers = g_slist_remove(prim->watchers, watcher);
 
246
 
 
247
        g_attrib_unref(gatt->attrib);
 
248
}
 
249
 
 
250
static int characteristic_set_value(struct characteristic *chr,
 
251
                                        const uint8_t *value, size_t vlen)
 
252
{
 
253
        chr->value = g_try_realloc(chr->value, vlen);
 
254
        if (chr->value == NULL)
 
255
                return -ENOMEM;
 
256
 
 
257
        memcpy(chr->value, value, vlen);
 
258
        chr->vlen = vlen;
 
259
 
 
260
        return 0;
 
261
}
 
262
 
 
263
static void update_watchers(gpointer data, gpointer user_data)
 
264
{
 
265
        struct watcher *w = data;
 
266
        struct characteristic *chr = user_data;
 
267
        DBusMessage *msg;
 
268
 
 
269
        msg = dbus_message_new_method_call(w->name, w->path,
 
270
                                "org.bluez.Watcher", "ValueChanged");
 
271
        if (msg == NULL)
 
272
                return;
 
273
 
 
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);
 
277
 
 
278
        dbus_message_set_no_reply(msg, TRUE);
 
279
        g_dbus_send_message(connection, msg);
 
280
}
 
281
 
 
282
static void events_handler(const uint8_t *pdu, uint16_t len,
 
283
                                                        gpointer user_data)
 
284
{
 
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]);
 
291
        uint16_t olen;
 
292
 
 
293
        for (lprim = gatt->primary, prim = NULL, chr = NULL; lprim;
 
294
                                                lprim = lprim->next) {
 
295
                prim = lprim->data;
 
296
 
 
297
                lchr = g_slist_find_custom(prim->chars,
 
298
                        GUINT_TO_POINTER(handle), characteristic_handle_cmp);
 
299
                if (lchr) {
 
300
                        chr = lchr->data;
 
301
                        break;
 
302
                }
 
303
        }
 
304
 
 
305
        if (chr == NULL) {
 
306
                DBG("Attribute handle 0x%02x not found", handle);
 
307
                return;
 
308
        }
 
309
 
 
310
        switch (pdu[0]) {
 
311
        case ATT_OP_HANDLE_IND:
 
312
                olen = enc_confirmation(opdu, sizeof(opdu));
 
313
                g_attrib_send(gatt->attrib, opdu[0], opdu, olen,
 
314
                                                NULL, NULL, NULL);
 
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);
 
318
 
 
319
                g_slist_foreach(prim->watchers, update_watchers, chr);
 
320
                break;
 
321
        }
 
322
}
 
323
 
 
324
static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
 
325
                                                        gpointer user_data);
 
326
 
 
327
static void attrib_destroy(gpointer user_data)
 
328
{
 
329
        struct gatt_service *gatt = user_data;
 
330
 
 
331
        gatt->attrib = NULL;
 
332
}
 
333
 
 
334
static void attrib_disconnect(gpointer user_data)
 
335
{
 
336
        struct gatt_service *gatt = user_data;
 
337
 
 
338
        /* Remote initiated disconnection only */
 
339
        g_attrib_unref(gatt->attrib);
 
340
}
 
341
 
 
342
static void connect_cb(GIOChannel *chan, GError *gerr, gpointer user_data)
 
343
{
 
344
        struct gatt_service *gatt = user_data;
 
345
        guint atid;
 
346
 
 
347
        if (gerr) {
 
348
                error("%s", gerr->message);
 
349
                goto fail;
 
350
        }
 
351
 
 
352
        if (gatt->attrib == NULL)
 
353
                return;
 
354
 
 
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,
 
361
                                        ATT_OP_HANDLE_IND,
 
362
                                        events_handler, gatt, NULL);
 
363
                return;
 
364
        }
 
365
 
 
366
        atid = gatt_discover_primary(gatt->attrib, 0x0001, 0xffff, NULL,
 
367
                                                        primary_cb, gatt);
 
368
        if (atid == 0)
 
369
                goto fail;
 
370
 
 
371
        gatt->atid = atid;
 
372
 
 
373
        return;
 
374
fail:
 
375
        g_attrib_unref(gatt->attrib);
 
376
}
 
377
 
 
378
static DBusMessage *get_characteristics(DBusConnection *conn,
 
379
                                                DBusMessage *msg, void *data)
 
380
{
 
381
        struct primary *prim = data;
 
382
        DBusMessage *reply;
 
383
        DBusMessageIter iter, array;
 
384
        GSList *l;
 
385
 
 
386
        reply = dbus_message_new_method_return(msg);
 
387
        if (reply == NULL)
 
388
                return NULL;
 
389
 
 
390
        dbus_message_iter_init_append(reply, &iter);
 
391
 
 
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);
 
400
 
 
401
        for (l = prim->chars; l; l = l->next) {
 
402
                struct characteristic *chr = l->data;
 
403
                DBusMessageIter sub;
 
404
 
 
405
                DBG("path %s", chr->path);
 
406
 
 
407
                dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY,
 
408
                                                                NULL, &sub);
 
409
 
 
410
                dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH,
 
411
                                                                &chr->path);
 
412
 
 
413
                append_char_dict(&sub, chr);
 
414
 
 
415
                dbus_message_iter_close_container(&array, &sub);
 
416
        }
 
417
 
 
418
        dbus_message_iter_close_container(&iter, &array);
 
419
 
 
420
        return reply;
 
421
}
 
422
 
 
423
static int l2cap_connect(struct gatt_service *gatt, GError **gerr,
 
424
                                                                gboolean listen)
 
425
{
 
426
        GIOChannel *io;
 
427
 
 
428
        if (gatt->attrib != NULL) {
 
429
                gatt->attrib = g_attrib_ref(gatt->attrib);
 
430
                return 0;
 
431
        }
 
432
 
 
433
        /*
 
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.
 
437
         */
 
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,
 
443
                        BT_IO_OPT_INVALID);
 
444
        if (!io)
 
445
                return -1;
 
446
 
 
447
        gatt->attrib = g_attrib_new(io);
 
448
        g_io_channel_unref(io);
 
449
        gatt->listen = listen;
 
450
 
 
451
        g_attrib_set_destroy_function(gatt->attrib, attrib_destroy, gatt);
 
452
        g_attrib_set_disconnect_function(gatt->attrib, attrib_disconnect,
 
453
                                                                        gatt);
 
454
 
 
455
        return 0;
 
456
}
 
457
 
 
458
static DBusMessage *register_watcher(DBusConnection *conn,
 
459
                                                DBusMessage *msg, void *data)
 
460
{
 
461
        const char *sender = dbus_message_get_sender(msg);
 
462
        struct primary *prim = data;
 
463
        struct watcher *watcher;
 
464
        GError *gerr = NULL;
 
465
        char *path;
 
466
 
 
467
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
 
468
                                                        DBUS_TYPE_INVALID))
 
469
                return invalid_args(msg);
 
470
 
 
471
        if (l2cap_connect(prim->gatt, &gerr, TRUE) < 0) {
 
472
                DBusMessage *reply;
 
473
                reply = g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
474
                                                        "%s", gerr->message);
 
475
                g_error_free(gerr);
 
476
 
 
477
                return reply;
 
478
        }
 
479
 
 
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);
 
486
 
 
487
        prim->watchers = g_slist_append(prim->watchers, watcher);
 
488
 
 
489
        return dbus_message_new_method_return(msg);
 
490
}
 
491
 
 
492
static DBusMessage *unregister_watcher(DBusConnection *conn,
 
493
                                                DBusMessage *msg, void *data)
 
494
{
 
495
        const char *sender = dbus_message_get_sender(msg);
 
496
        struct primary *prim = data;
 
497
        struct watcher *watcher, *match;
 
498
        GSList *l;
 
499
        char *path;
 
500
 
 
501
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
 
502
                                                        DBUS_TYPE_INVALID))
 
503
                return invalid_args(msg);
 
504
 
 
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);
 
509
        watcher_free(match);
 
510
        if (!l)
 
511
                return not_authorized(msg);
 
512
 
 
513
        watcher = l->data;
 
514
        g_dbus_remove_watch(conn, watcher->id);
 
515
        prim->watchers = g_slist_remove(prim->watchers, watcher);
 
516
        watcher_free(watcher);
 
517
 
 
518
        return dbus_message_new_method_return(msg);
 
519
}
 
520
 
 
521
static GDBusMethodTable prim_methods[] = {
 
522
        { "GetCharacteristics", "",     "a{oa{sv}}", get_characteristics},
 
523
        { "RegisterCharacteristicsWatcher",     "o", "",
 
524
                                                register_watcher        },
 
525
        { "UnregisterCharacteristicsWatcher",   "o", "",
 
526
                                                unregister_watcher      },
 
527
        { }
 
528
};
 
529
 
 
530
static DBusMessage *set_value(DBusConnection *conn, DBusMessage *msg,
 
531
                        DBusMessageIter *iter, struct characteristic *chr)
 
532
{
 
533
        struct gatt_service *gatt = chr->prim->gatt;
 
534
        DBusMessageIter sub;
 
535
        GError *gerr = NULL;
 
536
        uint8_t *value;
 
537
        int len;
 
538
 
 
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);
 
542
 
 
543
        dbus_message_iter_recurse(iter, &sub);
 
544
 
 
545
        dbus_message_iter_get_fixed_array(&sub, &value, &len);
 
546
 
 
547
        if (l2cap_connect(gatt, &gerr, FALSE) < 0) {
 
548
                DBusMessage *reply;
 
549
                reply = g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
550
                                                        "%s", gerr->message);
 
551
                g_error_free(gerr);
 
552
 
 
553
                return reply;
 
554
        }
 
555
 
 
556
        gatt_write_cmd(gatt->attrib, chr->handle, value, len, NULL, NULL);
 
557
 
 
558
        characteristic_set_value(chr, value, len);
 
559
 
 
560
        return dbus_message_new_method_return(msg);
 
561
}
 
562
 
 
563
static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
 
564
                                                                void *data)
 
565
{
 
566
        struct characteristic *chr = data;
 
567
        DBusMessage *reply;
 
568
        DBusMessageIter iter;
 
569
 
 
570
        reply = dbus_message_new_method_return(msg);
 
571
        if (!reply)
 
572
                return NULL;
 
573
 
 
574
        dbus_message_iter_init_append(reply, &iter);
 
575
 
 
576
        append_char_dict(&iter, chr);
 
577
 
 
578
        return reply;
 
579
}
 
580
 
 
581
static DBusMessage *set_property(DBusConnection *conn,
 
582
                                        DBusMessage *msg, void *data)
 
583
{
 
584
        struct characteristic *chr = data;
 
585
        DBusMessageIter iter;
 
586
        DBusMessageIter sub;
 
587
        const char *property;
 
588
 
 
589
        if (!dbus_message_iter_init(msg, &iter))
 
590
                return invalid_args(msg);
 
591
 
 
592
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 
593
                return invalid_args(msg);
 
594
 
 
595
        dbus_message_iter_get_basic(&iter, &property);
 
596
        dbus_message_iter_next(&iter);
 
597
 
 
598
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
 
599
                return invalid_args(msg);
 
600
 
 
601
        dbus_message_iter_recurse(&iter, &sub);
 
602
 
 
603
        if (g_str_equal("Value", property))
 
604
                return set_value(conn, msg, &sub, chr);
 
605
 
 
606
        return invalid_args(msg);
 
607
}
 
608
 
 
609
static GDBusMethodTable char_methods[] = {
 
610
        { "GetProperties",      "",     "a{sv}", get_properties },
 
611
        { "SetProperty",        "sv",   "",     set_property,
 
612
                                                G_DBUS_METHOD_FLAG_ASYNC},
 
613
        { }
 
614
};
 
615
 
 
616
static void register_primary(struct gatt_service *gatt)
 
617
{
 
618
        GSList *l;
 
619
 
 
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);
 
626
 
 
627
                device_add_service(gatt->dev, prim->path);
 
628
        }
 
629
}
 
630
 
 
631
static char *characteristic_list_to_string(GSList *chars)
 
632
{
 
633
        GString *characteristics;
 
634
        GSList *l;
 
635
 
 
636
        characteristics = g_string_new(NULL);
 
637
 
 
638
        for (l = chars; l; l = l->next) {
 
639
                struct characteristic *chr = l->data;
 
640
                uuid_t *uuid128;
 
641
                char chr_str[64];
 
642
                char uuidstr[MAX_LEN_UUID_STR];
 
643
 
 
644
                memset(chr_str, 0, sizeof(chr_str));
 
645
 
 
646
                uuid128 = sdp_uuid_to_uuid128(&chr->type);
 
647
                sdp_uuid2strn(uuid128, uuidstr, MAX_LEN_UUID_STR);
 
648
 
 
649
                bt_free(uuid128);
 
650
 
 
651
                snprintf(chr_str, sizeof(chr_str), "%04X#%02X#%04X#%s ",
 
652
                                chr->handle, chr->perm, chr->end, uuidstr);
 
653
 
 
654
                characteristics = g_string_append(characteristics, chr_str);
 
655
        }
 
656
 
 
657
        return g_string_free(characteristics, FALSE);
 
658
}
 
659
 
 
660
static void store_characteristics(struct gatt_service *gatt,
 
661
                                                        struct primary *prim)
 
662
{
 
663
        char *characteristics;
 
664
 
 
665
        characteristics = characteristic_list_to_string(prim->chars);
 
666
 
 
667
        write_device_characteristics(&gatt->sba, &gatt->dba, prim->start,
 
668
                                                        characteristics);
 
669
 
 
670
        g_free(characteristics);
 
671
}
 
672
 
 
673
static void register_characteristics(struct primary *prim)
 
674
{
 
675
        GSList *lc;
 
676
 
 
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);
 
683
        }
 
684
}
 
685
 
 
686
static GSList *string_to_characteristic_list(struct primary *prim,
 
687
                                                        const char *str)
 
688
{
 
689
        GSList *l = NULL;
 
690
        char **chars;
 
691
        int i;
 
692
 
 
693
        if (str == NULL)
 
694
                return NULL;
 
695
 
 
696
        chars = g_strsplit(str, " ", 0);
 
697
        if (chars == NULL)
 
698
                return NULL;
 
699
 
 
700
        for (i = 0; chars[i]; i++) {
 
701
                struct characteristic *chr;
 
702
                char uuidstr[MAX_LEN_UUID_STR + 1];
 
703
                int ret;
 
704
 
 
705
                chr = g_new0(struct characteristic, 1);
 
706
 
 
707
                ret = sscanf(chars[i], "%04hX#%02hhX#%04hX#%s", &chr->handle,
 
708
                                &chr->perm, &chr->end, uuidstr);
 
709
                if (ret < 4) {
 
710
                        g_free(chr);
 
711
                        continue;
 
712
                }
 
713
 
 
714
                chr->prim = prim;
 
715
                chr->path = g_strdup_printf("%s/characteristic%04x",
 
716
                                                prim->path, chr->handle);
 
717
 
 
718
                bt_string2uuid(&chr->type, uuidstr);
 
719
 
 
720
                l = g_slist_append(l, chr);
 
721
        }
 
722
 
 
723
        g_strfreev(chars);
 
724
 
 
725
        return l;
 
726
}
 
727
 
 
728
static void load_characteristics(gpointer data, gpointer user_data)
 
729
{
 
730
        struct primary *prim = data;
 
731
        struct gatt_service *gatt = user_data;
 
732
        GSList *chrs_list;
 
733
        char *str;
 
734
 
 
735
        if (prim->chars) {
 
736
                DBG("Characteristics already loaded");
 
737
                return;
 
738
        }
 
739
 
 
740
        str = read_device_characteristics(&gatt->sba, &gatt->dba, prim->start);
 
741
        if (str == NULL)
 
742
                return;
 
743
 
 
744
        chrs_list = string_to_characteristic_list(prim, str);
 
745
 
 
746
        free(str);
 
747
 
 
748
        if (chrs_list == NULL)
 
749
                return;
 
750
 
 
751
        prim->chars = chrs_list;
 
752
        register_characteristics(prim);
 
753
 
 
754
        return;
 
755
}
 
756
 
 
757
static void store_attribute(struct gatt_service *gatt, uint16_t handle,
 
758
                                uint16_t type, uint8_t *value, gsize len)
 
759
{
 
760
        uuid_t uuid;
 
761
        char *str, *uuidstr, *tmp;
 
762
        guint i;
 
763
 
 
764
        str = g_malloc0(MAX_LEN_UUID_STR + len * 2 + 1);
 
765
 
 
766
        sdp_uuid16_create(&uuid, type);
 
767
        uuidstr = bt_uuid2string(&uuid);
 
768
        strcpy(str, uuidstr);
 
769
        g_free(uuidstr);
 
770
 
 
771
        str[MAX_LEN_UUID_STR - 1] = '#';
 
772
 
 
773
        for (i = 0, tmp = str + MAX_LEN_UUID_STR; i < len; i++, tmp += 2)
 
774
                sprintf(tmp, "%02X", value[i]);
 
775
 
 
776
        write_device_attribute(&gatt->sba, &gatt->dba, handle, str);
 
777
        g_free(str);
 
778
}
 
779
 
 
780
static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
 
781
                                                        gpointer user_data)
 
782
{
 
783
        struct query_data *current = user_data;
 
784
        struct gatt_service *gatt = current->prim->gatt;
 
785
        struct characteristic *chr = current->chr;
 
786
 
 
787
        if (status != 0)
 
788
                goto done;
 
789
 
 
790
        g_free(chr->desc);
 
791
 
 
792
        chr->desc = g_malloc(len);
 
793
        memcpy(chr->desc, pdu + 1, len - 1);
 
794
        chr->desc[len - 1] = '\0';
 
795
 
 
796
        store_attribute(gatt, current->handle, GATT_CHARAC_USER_DESC_UUID,
 
797
                                                (void *) chr->desc, len);
 
798
done:
 
799
        g_attrib_unref(gatt->attrib);
 
800
        g_free(current);
 
801
}
 
802
 
 
803
static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
 
804
                                                                gpointer user_data)
 
805
{
 
806
        struct query_data *current = user_data;
 
807
        struct gatt_service *gatt = current->prim->gatt;
 
808
        struct characteristic *chr = current->chr;
 
809
 
 
810
        if (status != 0)
 
811
                goto done;
 
812
 
 
813
        if (len < 8)
 
814
                goto done;
 
815
 
 
816
        g_free(chr->format);
 
817
 
 
818
        chr->format = g_new0(struct format, 1);
 
819
        memcpy(chr->format, pdu + 1, 7);
 
820
 
 
821
        store_attribute(gatt, current->handle, GATT_CHARAC_FMT_UUID,
 
822
                                (void *) chr->format, sizeof(*chr->format));
 
823
 
 
824
done:
 
825
        g_attrib_unref(gatt->attrib);
 
826
        g_free(current);
 
827
}
 
828
 
 
829
static void update_char_value(guint8 status, const guint8 *pdu,
 
830
                                        guint16 len, gpointer user_data)
 
831
{
 
832
        struct query_data *current = user_data;
 
833
        struct gatt_service *gatt = current->prim->gatt;
 
834
        struct characteristic *chr = current->chr;
 
835
 
 
836
        if (status == 0)
 
837
                characteristic_set_value(chr, pdu + 1, len - 1);
 
838
 
 
839
        g_attrib_unref(gatt->attrib);
 
840
        g_free(current);
 
841
}
 
842
 
 
843
static int uuid_desc16_cmp(uuid_t *uuid, guint16 desc)
 
844
{
 
845
        uuid_t u16;
 
846
 
 
847
        sdp_uuid16_create(&u16, desc);
 
848
 
 
849
        return sdp_uuid_cmp(uuid, &u16);
 
850
}
 
851
 
 
852
static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
 
853
                                                        gpointer user_data)
 
854
{
 
855
        struct query_data *current = user_data;
 
856
        struct gatt_service *gatt = current->prim->gatt;
 
857
        struct att_data_list *list;
 
858
        guint8 format;
 
859
        int i;
 
860
 
 
861
        if (status != 0)
 
862
                goto done;
 
863
 
 
864
        DBG("Find Information Response received");
 
865
 
 
866
        list = dec_find_info_resp(pdu, plen, &format);
 
867
        if (list == NULL)
 
868
                goto done;
 
869
 
 
870
        for (i = 0; i < list->num; i++) {
 
871
                guint16 handle;
 
872
                uuid_t uuid;
 
873
                uint8_t *info = list->data[i];
 
874
                struct query_data *qfmt;
 
875
 
 
876
                handle = att_get_u16(info);
 
877
 
 
878
                if (format == 0x01) {
 
879
                        sdp_uuid16_create(&uuid, att_get_u16(&info[2]));
 
880
                } else {
 
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
 
884
                         * 0x02 yet. */
 
885
                        continue;
 
886
                }
 
887
                qfmt = g_new0(struct query_data, 1);
 
888
                qfmt->prim = current->prim;
 
889
                qfmt->chr = current->chr;
 
890
                qfmt->handle = handle;
 
891
 
 
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,
 
895
                                                                        qfmt);
 
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);
 
900
                } else
 
901
                        g_free(qfmt);
 
902
        }
 
903
 
 
904
        att_data_list_free(list);
 
905
done:
 
906
        g_attrib_unref(gatt->attrib);
 
907
        g_free(current);
 
908
}
 
909
 
 
910
static void update_all_chars(gpointer data, gpointer user_data)
 
911
{
 
912
        struct query_data *qdesc, *qvalue;
 
913
        struct characteristic *chr = data;
 
914
        struct primary *prim = user_data;
 
915
        struct gatt_service *gatt = prim->gatt;
 
916
 
 
917
        qdesc = g_new0(struct query_data, 1);
 
918
        qdesc->prim = prim;
 
919
        qdesc->chr = chr;
 
920
 
 
921
        gatt->attrib = g_attrib_ref(gatt->attrib);
 
922
        gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb,
 
923
                                                                        qdesc);
 
924
 
 
925
        qvalue = g_new0(struct query_data, 1);
 
926
        qvalue->prim = prim;
 
927
        qvalue->chr = chr;
 
928
 
 
929
        gatt->attrib = g_attrib_ref(gatt->attrib);
 
930
        gatt_read_char(gatt->attrib, chr->handle, update_char_value, qvalue);
 
931
}
 
932
 
 
933
static void char_discovered_cb(guint8 status, const guint8 *pdu, guint16 plen,
 
934
                                                        gpointer user_data)
 
935
{
 
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;
 
941
        int i;
 
942
 
 
943
        if (status == ATT_ECODE_ATTR_NOT_FOUND)
 
944
                goto done;
 
945
 
 
946
        if (status != 0) {
 
947
                DBG("Discover all characteristics failed: %s",
 
948
                                                att_ecode2str(status));
 
949
 
 
950
                goto fail;
 
951
        }
 
952
 
 
953
        DBG("Read by Type Response received");
 
954
 
 
955
        list = dec_read_by_type_resp(pdu, plen);
 
956
        if (list == NULL)
 
957
                goto fail;
 
958
 
 
959
        for (i = 0, last = 0; i < list->num; i++) {
 
960
                uint8_t *decl = list->data[i];
 
961
                struct characteristic *chr;
 
962
 
 
963
                chr = g_new0(struct characteristic, 1);
 
964
                chr->prim = prim;
 
965
                chr->perm = decl[2];
 
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]));
 
972
                } else
 
973
                        sdp_uuid128_create(&chr->type, &decl[5]);
 
974
 
 
975
                if (previous_end) {
 
976
                        *previous_end = att_get_u16(decl);
 
977
                }
 
978
 
 
979
                last = chr->handle;
 
980
                previous_end = &chr->end;
 
981
 
 
982
                prim->chars = g_slist_append(prim->chars, chr);
 
983
        }
 
984
 
 
985
        if (previous_end)
 
986
                *previous_end = prim->end;
 
987
 
 
988
        att_data_list_free(list);
 
989
 
 
990
        if (last >= prim->end)
 
991
                goto done;
 
992
 
 
993
        /* Fetch remaining characteristics for the CURRENT primary service */
 
994
        gatt_discover_char(gatt->attrib, last + 1, prim->end,
 
995
                                                char_discovered_cb, current);
 
996
 
 
997
        return;
 
998
 
 
999
done:
 
1000
        store_characteristics(gatt, prim);
 
1001
        register_characteristics(prim);
 
1002
 
 
1003
        g_slist_foreach(prim->chars, update_all_chars, prim);
 
1004
 
 
1005
fail:
 
1006
        g_attrib_unref(gatt->attrib);
 
1007
        g_free(current);
 
1008
}
 
1009
 
 
1010
static void *attr_data_from_string(const char *str)
 
1011
{
 
1012
        uint8_t *data;
 
1013
        int size, i;
 
1014
        char tmp[3];
 
1015
 
 
1016
        size = strlen(str) / 2;
 
1017
        data = g_try_malloc0(size);
 
1018
        if (data == NULL)
 
1019
                return NULL;
 
1020
 
 
1021
        tmp[2] = '\0';
 
1022
        for (i = 0; i < size; i++) {
 
1023
                memcpy(tmp, str + (i * 2), 2);
 
1024
                data[i] = (uint8_t) strtol(tmp, NULL, 16);
 
1025
        }
 
1026
 
 
1027
        return data;
 
1028
}
 
1029
 
 
1030
static int find_primary(gconstpointer a, gconstpointer b)
 
1031
{
 
1032
        const struct primary *primary = a;
 
1033
        uint16_t handle = GPOINTER_TO_UINT(b);
 
1034
 
 
1035
        if (handle < primary->start)
 
1036
                return -1;
 
1037
 
 
1038
        if (handle > primary->end)
 
1039
                return -1;
 
1040
 
 
1041
        return 0;
 
1042
}
 
1043
 
 
1044
static int find_characteristic(gconstpointer a, gconstpointer b)
 
1045
{
 
1046
        const struct characteristic *chr = a;
 
1047
        uint16_t handle = GPOINTER_TO_UINT(b);
 
1048
 
 
1049
        if (handle < chr->handle)
 
1050
                return -1;
 
1051
 
 
1052
        if (handle > chr->end)
 
1053
                return -1;
 
1054
 
 
1055
        return 0;
 
1056
}
 
1057
 
 
1058
static void load_attribute_data(char *key, char *value, void *data)
 
1059
{
 
1060
        struct gatt_service *gatt = data;
 
1061
        struct characteristic *chr;
 
1062
        struct primary *primary;
 
1063
        char addr[18], dst[18];
 
1064
        uint16_t handle;
 
1065
        uuid_t uuid;
 
1066
        GSList *l;
 
1067
        guint h;
 
1068
 
 
1069
        if (sscanf(key, "%17s#%04hX", addr, &handle) < 2)
 
1070
                return;
 
1071
 
 
1072
        ba2str(&gatt->dba, dst);
 
1073
 
 
1074
        if (strcmp(addr, dst) != 0)
 
1075
                return;
 
1076
 
 
1077
        h = handle;
 
1078
 
 
1079
        l = g_slist_find_custom(gatt->primary, GUINT_TO_POINTER(h),
 
1080
                                                                find_primary);
 
1081
        if (!l)
 
1082
                return;
 
1083
 
 
1084
        primary = l->data;
 
1085
 
 
1086
        l = g_slist_find_custom(primary->chars, GUINT_TO_POINTER(h),
 
1087
                                                        find_characteristic);
 
1088
        if (!l)
 
1089
                return;
 
1090
 
 
1091
        chr = l->data;
 
1092
 
 
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)
 
1098
                return;
 
1099
 
 
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);
 
1105
}
 
1106
 
 
1107
static char *primary_list_to_string(GSList *primary_list)
 
1108
{
 
1109
        GString *services;
 
1110
        GSList *l;
 
1111
 
 
1112
        services = g_string_new(NULL);
 
1113
 
 
1114
        for (l = primary_list; l; l = l->next) {
 
1115
                struct primary *primary = l->data;
 
1116
                uuid_t *uuid128;
 
1117
                char service[64];
 
1118
                char uuidstr[MAX_LEN_UUID_STR];
 
1119
 
 
1120
                memset(service, 0, sizeof(service));
 
1121
 
 
1122
                uuid128 = sdp_uuid_to_uuid128(&primary->uuid);
 
1123
                sdp_uuid2strn(uuid128, uuidstr, MAX_LEN_UUID_STR);
 
1124
 
 
1125
                bt_free(uuid128);
 
1126
 
 
1127
                snprintf(service, sizeof(service), "%04X#%04X#%s ",
 
1128
                                primary->start, primary->end, uuidstr);
 
1129
 
 
1130
                services = g_string_append(services, service);
 
1131
        }
 
1132
 
 
1133
        return g_string_free(services, FALSE);
 
1134
}
 
1135
 
 
1136
static GSList *string_to_primary_list(struct gatt_service *gatt,
 
1137
                                                        const char *str)
 
1138
{
 
1139
        GSList *l = NULL;
 
1140
        char **services;
 
1141
        int i;
 
1142
 
 
1143
        if (str == NULL)
 
1144
                return NULL;
 
1145
 
 
1146
        services = g_strsplit(str, " ", 0);
 
1147
        if (services == NULL)
 
1148
                return NULL;
 
1149
 
 
1150
        for (i = 0; services[i]; i++) {
 
1151
                struct primary *prim;
 
1152
                char uuidstr[MAX_LEN_UUID_STR + 1];
 
1153
                int ret;
 
1154
 
 
1155
                prim = g_new0(struct primary, 1);
 
1156
                prim->gatt = gatt;
 
1157
 
 
1158
                ret = sscanf(services[i], "%04hX#%04hX#%s", &prim->start,
 
1159
                                                        &prim->end, uuidstr);
 
1160
 
 
1161
                if (ret < 3) {
 
1162
                        g_free(prim);
 
1163
                        continue;
 
1164
                }
 
1165
 
 
1166
                prim->path = g_strdup_printf("%s/service%04x", gatt->path,
 
1167
                                                                prim->start);
 
1168
 
 
1169
                bt_string2uuid(&prim->uuid, uuidstr);
 
1170
 
 
1171
                l = g_slist_append(l, prim);
 
1172
        }
 
1173
 
 
1174
        g_strfreev(services);
 
1175
 
 
1176
        return l;
 
1177
}
 
1178
 
 
1179
static void store_primary_services(struct gatt_service *gatt)
 
1180
{
 
1181
       char *services;
 
1182
 
 
1183
       services = primary_list_to_string(gatt->primary);
 
1184
 
 
1185
       write_device_services(&gatt->sba, &gatt->dba, services);
 
1186
 
 
1187
       g_free(services);
 
1188
}
 
1189
 
 
1190
static gboolean load_primary_services(struct gatt_service *gatt)
 
1191
{
 
1192
        GSList *primary_list;
 
1193
        char *str;
 
1194
 
 
1195
        if (gatt->primary) {
 
1196
                DBG("Services already loaded");
 
1197
                return FALSE;
 
1198
        }
 
1199
 
 
1200
        str = read_device_services(&gatt->sba, &gatt->dba);
 
1201
        if (str == NULL)
 
1202
                return FALSE;
 
1203
 
 
1204
        primary_list = string_to_primary_list(gatt, str);
 
1205
 
 
1206
        free(str);
 
1207
 
 
1208
        if (primary_list == NULL)
 
1209
                return FALSE;
 
1210
 
 
1211
        gatt->primary = primary_list;
 
1212
        register_primary(gatt);
 
1213
 
 
1214
        g_slist_foreach(gatt->primary, load_characteristics, gatt);
 
1215
        read_device_attributes(&gatt->sba, load_attribute_data, gatt);
 
1216
 
 
1217
        return TRUE;
 
1218
}
 
1219
 
 
1220
static void discover_all_char(gpointer data, gpointer user_data)
 
1221
{
 
1222
        struct query_data *qchr;
 
1223
        struct gatt_service *gatt = user_data;
 
1224
        struct primary *prim = data;
 
1225
 
 
1226
        qchr = g_new0(struct query_data, 1);
 
1227
        qchr->prim = prim;
 
1228
 
 
1229
        gatt->attrib = g_attrib_ref(gatt->attrib);
 
1230
        gatt_discover_char(gatt->attrib, prim->start, prim->end,
 
1231
                                                char_discovered_cb, qchr);
 
1232
}
 
1233
 
 
1234
static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
 
1235
                                                        gpointer user_data)
 
1236
{
 
1237
        struct gatt_service *gatt = user_data;
 
1238
        struct att_data_list *list;
 
1239
        unsigned int i;
 
1240
        uint16_t end, start;
 
1241
 
 
1242
        if (status == ATT_ECODE_ATTR_NOT_FOUND) {
 
1243
                if (gatt->primary == NULL)
 
1244
                        goto done;
 
1245
 
 
1246
                store_primary_services(gatt);
 
1247
                register_primary(gatt);
 
1248
 
 
1249
                g_slist_foreach(gatt->primary, discover_all_char, gatt);
 
1250
                goto done;
 
1251
        }
 
1252
 
 
1253
        if (status != 0) {
 
1254
                error("Discover all primary services failed: %s",
 
1255
                                                att_ecode2str(status));
 
1256
                goto done;
 
1257
        }
 
1258
 
 
1259
        list = dec_read_by_grp_resp(pdu, plen);
 
1260
        if (list == NULL) {
 
1261
                error("Protocol error");
 
1262
                goto done;
 
1263
        }
 
1264
 
 
1265
        DBG("Read by Group Type Response received");
 
1266
 
 
1267
        for (i = 0, end = 0; i < list->num; i++) {
 
1268
                struct primary *prim;
 
1269
                uint8_t *info = list->data[i];
 
1270
 
 
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]);
 
1275
 
 
1276
                prim = g_new0(struct primary, 1);
 
1277
                prim->gatt = gatt;
 
1278
                prim->start = start;
 
1279
                prim->end = end;
 
1280
 
 
1281
                if (list->len == 6) {
 
1282
                        sdp_uuid16_create(&prim->uuid,
 
1283
                                        att_get_u16(&info[4]));
 
1284
 
 
1285
                } else if (list->len == 20) {
 
1286
                        /* FIXME: endianness */
 
1287
                        sdp_uuid128_create(&prim->uuid, &info[4]);
 
1288
                } else {
 
1289
                        DBG("ATT: Invalid Length field");
 
1290
                        g_free(prim);
 
1291
                        att_data_list_free(list);
 
1292
                        goto done;
 
1293
                }
 
1294
 
 
1295
                prim->path = g_strdup_printf("%s/service%04x", gatt->path,
 
1296
                                                                prim->start);
 
1297
 
 
1298
                gatt->primary = g_slist_append(gatt->primary, prim);
 
1299
        }
 
1300
 
 
1301
        att_data_list_free(list);
 
1302
 
 
1303
        if (end == 0) {
 
1304
                DBG("ATT: Invalid PDU format");
 
1305
                goto done;
 
1306
        }
 
1307
 
 
1308
        /*
 
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.
 
1312
         */
 
1313
        gatt->attrib = g_attrib_ref(gatt->attrib);
 
1314
        gatt->atid = gatt_discover_primary(gatt->attrib, end + 1, 0xffff, NULL,
 
1315
                                                        primary_cb, gatt);
 
1316
done:
 
1317
        g_attrib_unref(gatt->attrib);
 
1318
}
 
1319
 
 
1320
int attrib_client_register(struct btd_device *device, int psm)
 
1321
{
 
1322
        struct btd_adapter *adapter = device_get_adapter(device);
 
1323
        const char *path = device_get_path(device);
 
1324
        struct gatt_service *gatt;
 
1325
        bdaddr_t sba, dba;
 
1326
 
 
1327
        adapter_get_address(adapter, &sba);
 
1328
        device_get_address(device, &dba);
 
1329
 
 
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);
 
1336
        gatt->psm = psm;
 
1337
 
 
1338
        if (load_primary_services(gatt))
 
1339
                DBG("Primary services loaded");
 
1340
 
 
1341
        gatt_services = g_slist_append(gatt_services, gatt);
 
1342
 
 
1343
        return 0;
 
1344
}
 
1345
 
 
1346
void attrib_client_unregister(struct btd_device *device)
 
1347
{
 
1348
        struct gatt_service *gatt;
 
1349
        GSList *l, *lp, *lc;
 
1350
 
 
1351
        l = g_slist_find_custom(gatt_services, device, gatt_dev_cmp);
 
1352
        if (!l)
 
1353
                return;
 
1354
 
 
1355
        gatt = l->data;
 
1356
        gatt_services = g_slist_remove(gatt_services, gatt);
 
1357
 
 
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,
 
1363
                                                                CHAR_INTERFACE);
 
1364
                }
 
1365
                g_dbus_unregister_interface(connection, prim->path,
 
1366
                                                                CHAR_INTERFACE);
 
1367
        }
 
1368
 
 
1369
        gatt_service_free(gatt);
 
1370
}
 
1371
 
 
1372
int attrib_client_init(DBusConnection *conn)
 
1373
{
 
1374
 
 
1375
        connection = dbus_connection_ref(conn);
 
1376
 
 
1377
        /*
 
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.
 
1381
         */
 
1382
 
 
1383
        return 0;
 
1384
}
 
1385
 
 
1386
void attrib_client_exit(void)
 
1387
{
 
1388
        dbus_connection_unref(connection);
 
1389
}