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

« back to all changes in this revision

Viewing changes to plugins/service.c

  • Committer: Bazaar Package Importer
  • Author(s): Mario Limonciello
  • Date: 2008-10-07 12:10:29 UTC
  • Revision ID: james.westby@ubuntu.com-20081007121029-4gup4fmmh2vfo5nh
Tags: upstream-4.12
ImportĀ upstreamĀ versionĀ 4.12

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) 2006-2007  Nokia Corporation
 
6
 *  Copyright (C) 2004-2008  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
#ifdef HAVE_CONFIG_H
 
26
#include <config.h>
 
27
#endif
 
28
 
 
29
#include <errno.h>
 
30
#include <stdlib.h>
 
31
#include <string.h>
 
32
 
 
33
#include <bluetooth/bluetooth.h>
 
34
#include <bluetooth/hci.h>
 
35
#include <bluetooth/hci_lib.h>
 
36
#include <bluetooth/sdp.h>
 
37
#include <bluetooth/sdp_lib.h>
 
38
 
 
39
#include <gdbus.h>
 
40
 
 
41
#include "sdpd.h"
 
42
#include "sdp-xml.h"
 
43
#include "plugin.h"
 
44
#include "adapter.h"
 
45
#include "error.h"
 
46
#include "logging.h"
 
47
 
 
48
#define SERVICE_INTERFACE "org.bluez.Service"
 
49
 
 
50
static DBusConnection *connection = NULL;
 
51
 
 
52
struct record_data {
 
53
        uint32_t handle;
 
54
        char *sender;
 
55
        guint listener_id;
 
56
        struct service_adapter *serv_adapter;
 
57
};
 
58
 
 
59
struct context_data {
 
60
        sdp_record_t *record;
 
61
        sdp_data_t attr_data;
 
62
        struct sdp_xml_data *stack_head;
 
63
        uint16_t attr_id;
 
64
};
 
65
 
 
66
struct pending_auth {
 
67
        DBusConnection *conn;
 
68
        DBusMessage *msg;
 
69
        char *sender;
 
70
        bdaddr_t dst;
 
71
        char uuid[MAX_LEN_UUID_STR];
 
72
};
 
73
 
 
74
struct service_adapter {
 
75
        struct btd_adapter *adapter;
 
76
        GSList *pending_list;
 
77
        GSList *records;
 
78
};
 
79
 
 
80
static int compute_seq_size(sdp_data_t *data)
 
81
{
 
82
        int unit_size = data->unitSize;
 
83
        sdp_data_t *seq = data->val.dataseq;
 
84
 
 
85
        for (; seq; seq = seq->next)
 
86
                unit_size += seq->unitSize;
 
87
 
 
88
        return unit_size;
 
89
}
 
90
 
 
91
static void element_start(GMarkupParseContext *context,
 
92
                const gchar *element_name, const gchar **attribute_names,
 
93
                const gchar **attribute_values, gpointer user_data, GError **err)
 
94
{
 
95
        struct context_data *ctx_data = user_data;
 
96
 
 
97
        if (!strcmp(element_name, "record"))
 
98
                return;
 
99
 
 
100
        if (!strcmp(element_name, "attribute")) {
 
101
                int i;
 
102
                for (i = 0; attribute_names[i]; i++) {
 
103
                        if (!strcmp(attribute_names[i], "id")) {
 
104
                                ctx_data->attr_id = strtol(attribute_values[i], 0, 0);
 
105
                                break;
 
106
                        }
 
107
                }
 
108
                debug("New attribute 0x%04x", ctx_data->attr_id);
 
109
                return;
 
110
        }
 
111
 
 
112
        if (ctx_data->stack_head) {
 
113
                struct sdp_xml_data *newelem = sdp_xml_data_alloc();
 
114
                newelem->next = ctx_data->stack_head;
 
115
                ctx_data->stack_head = newelem;
 
116
        } else {
 
117
                ctx_data->stack_head = sdp_xml_data_alloc();
 
118
                ctx_data->stack_head->next = NULL;
 
119
        }
 
120
 
 
121
        if (!strcmp(element_name, "sequence"))
 
122
                ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
 
123
        else if (!strcmp(element_name, "alternate"))
 
124
                ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
 
125
        else {
 
126
                int i;
 
127
                /* Parse value, name, encoding */
 
128
                for (i = 0; attribute_names[i]; i++) {
 
129
                        if (!strcmp(attribute_names[i], "value")) {
 
130
                                int curlen = strlen(ctx_data->stack_head->text);
 
131
                                int attrlen = strlen(attribute_values[i]);
 
132
 
 
133
                                /* Ensure we're big enough */
 
134
                                while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) {
 
135
                                        sdp_xml_data_expand(ctx_data->stack_head);
 
136
                                }
 
137
 
 
138
                                memcpy(ctx_data->stack_head->text + curlen,
 
139
                                                attribute_values[i], attrlen);
 
140
                                ctx_data->stack_head->text[curlen + attrlen] = '\0';
 
141
                        }
 
142
 
 
143
                        if (!strcmp(attribute_names[i], "encoding")) {
 
144
                                if (!strcmp(attribute_values[i], "hex"))
 
145
                                        ctx_data->stack_head->type = 1;
 
146
                        }
 
147
 
 
148
                        if (!strcmp(attribute_names[i], "name")) {
 
149
                                ctx_data->stack_head->name = strdup(attribute_values[i]);
 
150
                        }
 
151
                }
 
152
 
 
153
                ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
 
154
                                ctx_data->stack_head, ctx_data->record);
 
155
 
 
156
                if (ctx_data->stack_head->data == NULL)
 
157
                        error("Can't parse element %s", element_name);
 
158
        }
 
159
}
 
160
 
 
161
static void element_end(GMarkupParseContext *context,
 
162
                const gchar *element_name, gpointer user_data, GError **err)
 
163
{
 
164
        struct context_data *ctx_data = user_data;
 
165
        struct sdp_xml_data *elem;
 
166
 
 
167
        if (!strcmp(element_name, "record"))
 
168
                return;
 
169
 
 
170
        if (!strcmp(element_name, "attribute")) {
 
171
                if (ctx_data->stack_head && ctx_data->stack_head->data) {
 
172
                        int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
 
173
                                                        ctx_data->stack_head->data);
 
174
                        if (ret == -1)
 
175
                                debug("Trouble adding attribute\n");
 
176
 
 
177
                        ctx_data->stack_head->data = NULL;
 
178
                        sdp_xml_data_free(ctx_data->stack_head);
 
179
                        ctx_data->stack_head = NULL;
 
180
                } else {
 
181
                        debug("No data for attribute 0x%04x\n", ctx_data->attr_id);
 
182
                }
 
183
                return;
 
184
        }
 
185
 
 
186
        if (!strcmp(element_name, "sequence")) {
 
187
                ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
 
188
 
 
189
                if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
 
190
                        ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
 
191
                        ctx_data->stack_head->data->dtd = SDP_SEQ32;
 
192
                } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
 
193
                        ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
 
194
                        ctx_data->stack_head->data->dtd = SDP_SEQ16;
 
195
                } else {
 
196
                        ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
 
197
                }
 
198
        } else if (!strcmp(element_name, "alternate")) {
 
199
                ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
 
200
 
 
201
                if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
 
202
                        ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
 
203
                        ctx_data->stack_head->data->dtd = SDP_ALT32;
 
204
                } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
 
205
                        ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
 
206
                        ctx_data->stack_head->data->dtd = SDP_ALT16;
 
207
                } else {
 
208
                        ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
 
209
                }
 
210
        }
 
211
 
 
212
        if (ctx_data->stack_head->next && ctx_data->stack_head->data &&
 
213
                                        ctx_data->stack_head->next->data) {
 
214
                switch (ctx_data->stack_head->next->data->dtd) {
 
215
                case SDP_SEQ8:
 
216
                case SDP_SEQ16:
 
217
                case SDP_SEQ32:
 
218
                case SDP_ALT8:
 
219
                case SDP_ALT16:
 
220
                case SDP_ALT32:
 
221
                        ctx_data->stack_head->next->data->val.dataseq =
 
222
                                sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq,
 
223
                                                                ctx_data->stack_head->data);
 
224
                        ctx_data->stack_head->data = NULL;
 
225
                        break;
 
226
                }
 
227
 
 
228
                elem = ctx_data->stack_head;
 
229
                ctx_data->stack_head = ctx_data->stack_head->next;
 
230
 
 
231
                sdp_xml_data_free(elem);
 
232
        }
 
233
}
 
234
 
 
235
static GMarkupParser parser = {
 
236
        element_start, element_end, NULL, NULL, NULL
 
237
};
 
238
 
 
239
static sdp_record_t *sdp_xml_parse_record(const char *data, int size)
 
240
{
 
241
        GMarkupParseContext *ctx;
 
242
        struct context_data *ctx_data;
 
243
        sdp_record_t *record;
 
244
 
 
245
        ctx_data = malloc(sizeof(*ctx_data));
 
246
        if (!ctx_data)
 
247
                return NULL;
 
248
 
 
249
        record = sdp_record_alloc();
 
250
        if (!record) {
 
251
                free(ctx_data);
 
252
                return NULL;
 
253
        }
 
254
 
 
255
        memset(ctx_data, 0, sizeof(*ctx_data));
 
256
        ctx_data->record = record;
 
257
 
 
258
        ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
 
259
 
 
260
        if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
 
261
                error("XML parsing error");
 
262
                g_markup_parse_context_free(ctx);
 
263
                sdp_record_free(record);
 
264
                free(ctx_data);
 
265
                return NULL;
 
266
        }
 
267
 
 
268
        g_markup_parse_context_free(ctx);
 
269
 
 
270
        free(ctx_data);
 
271
 
 
272
        return record;
 
273
}
 
274
 
 
275
static struct record_data *find_record(struct service_adapter *serv_adapter,
 
276
                                        uint32_t handle, const char *sender)
 
277
{
 
278
        GSList *list;
 
279
 
 
280
        for (list = serv_adapter->records; list; list = list->next) {
 
281
                struct record_data *data = list->data;
 
282
                if (handle == data->handle && !strcmp(sender, data->sender))
 
283
                        return data;
 
284
        }
 
285
 
 
286
        return NULL;
 
287
}
 
288
 
 
289
static struct pending_auth *next_pending(struct service_adapter *serv_adapter)
 
290
{
 
291
        GSList *l = serv_adapter->pending_list;
 
292
 
 
293
        if (l) {
 
294
                struct pending_auth *auth = l->data;
 
295
                return auth;
 
296
        }
 
297
 
 
298
        return NULL;
 
299
}
 
300
 
 
301
static struct pending_auth *find_pending_by_sender(
 
302
                        struct service_adapter *serv_adapter,
 
303
                        const char *sender)
 
304
{
 
305
        GSList *l = serv_adapter->pending_list;
 
306
 
 
307
        for (; l; l = l->next) {
 
308
                struct pending_auth *auth = l->data;
 
309
                if (g_str_equal(auth->sender, sender))
 
310
                        return auth;
 
311
        }
 
312
 
 
313
        return NULL;
 
314
}
 
315
 
 
316
static void exit_callback(void *user_data)
 
317
{
 
318
        struct record_data *user_record = user_data;
 
319
        struct service_adapter *serv_adapter = user_record->serv_adapter;
 
320
        struct pending_auth *auth;
 
321
 
 
322
        debug("remove record");
 
323
 
 
324
        serv_adapter->records = g_slist_remove(serv_adapter->records,
 
325
                                                user_record);
 
326
 
 
327
        auth = find_pending_by_sender(serv_adapter, user_record->sender);
 
328
        if (auth) {
 
329
                serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
 
330
                                                        auth);
 
331
                g_free(auth);
 
332
        }
 
333
 
 
334
        remove_record_from_server(user_record->handle);
 
335
 
 
336
        g_free(user_record->sender);
 
337
        g_free(user_record);
 
338
}
 
339
 
 
340
static inline DBusMessage *invalid_arguments(DBusMessage *msg)
 
341
{
 
342
        return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
 
343
                                        "Invalid arguments in method call");
 
344
}
 
345
 
 
346
static inline DBusMessage *not_available(DBusMessage *msg)
 
347
{
 
348
        return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
 
349
                                                        "Not Available");
 
350
}
 
351
 
 
352
static inline DBusMessage *failed(DBusMessage *msg)
 
353
{
 
354
        return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Failed");
 
355
}
 
356
 
 
357
static inline DBusMessage *failed_strerror(DBusMessage *msg, int err)
 
358
{
 
359
        return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 
360
                        strerror(err));
 
361
}
 
362
 
 
363
static inline DBusMessage *not_authorized(DBusMessage *msg)
 
364
{
 
365
        return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized",
 
366
                                        "Not Authorized");
 
367
}
 
368
 
 
369
static inline DBusMessage *does_not_exist(DBusMessage *msg)
 
370
{
 
371
        return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist",
 
372
                                        "Does Not Exist");
 
373
}
 
374
 
 
375
static int add_xml_record(DBusConnection *conn, const char *sender,
 
376
                        struct service_adapter *serv_adapter,
 
377
                        const char *record, dbus_uint32_t *handle)
 
378
{
 
379
        struct record_data *user_record;
 
380
        sdp_record_t *sdp_record;
 
381
        bdaddr_t src;
 
382
 
 
383
        sdp_record = sdp_xml_parse_record(record, strlen(record));
 
384
        if (!sdp_record) {
 
385
                error("Parsing of XML service record failed");
 
386
                return -EIO;
 
387
        }
 
388
 
 
389
        adapter_get_address(serv_adapter->adapter, &src);
 
390
        if (add_record_to_server(&src, sdp_record) < 0) {
 
391
                error("Failed to register service record");
 
392
                sdp_record_free(sdp_record);
 
393
                return -EIO;
 
394
        }
 
395
 
 
396
        user_record = g_new0(struct record_data, 1);
 
397
        user_record->handle = sdp_record->handle;
 
398
        user_record->sender = g_strdup(sender);
 
399
        user_record->serv_adapter = serv_adapter;
 
400
        user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender,
 
401
                                        exit_callback, user_record, NULL);
 
402
 
 
403
        serv_adapter->records = g_slist_append(serv_adapter->records,
 
404
                                        user_record);
 
405
 
 
406
        debug("listener_id %d", user_record->listener_id);
 
407
 
 
408
        *handle = user_record->handle;
 
409
 
 
410
        return 0;
 
411
}
 
412
 
 
413
static DBusMessage *update_record(DBusConnection *conn, DBusMessage *msg,
 
414
                struct service_adapter *serv_adapter,
 
415
                dbus_uint32_t handle, sdp_record_t *sdp_record)
 
416
{
 
417
        bdaddr_t src;
 
418
        int err;
 
419
 
 
420
        if (remove_record_from_server(handle) < 0) {
 
421
                sdp_record_free(sdp_record);
 
422
                return g_dbus_create_error(msg,
 
423
                                ERROR_INTERFACE ".NotAvailable",
 
424
                                "Not Available");
 
425
        }
 
426
 
 
427
        adapter_get_address(serv_adapter->adapter, &src);
 
428
 
 
429
        sdp_record->handle = handle;
 
430
        err = add_record_to_server(&src, sdp_record);
 
431
        if (err < 0) {
 
432
                sdp_record_free(sdp_record);
 
433
                error("Failed to update the service record");
 
434
                return g_dbus_create_error(msg,
 
435
                                ERROR_INTERFACE ".Failed",
 
436
                                strerror(EIO));
 
437
        }
 
438
 
 
439
        return dbus_message_new_method_return(msg);
 
440
}
 
441
 
 
442
static DBusMessage *update_xml_record(DBusConnection *conn,
 
443
                                DBusMessage *msg,
 
444
                                struct service_adapter *serv_adapter)
 
445
{
 
446
        struct record_data *user_record;
 
447
        sdp_record_t *sdp_record;
 
448
        const char *record;
 
449
        dbus_uint32_t handle;
 
450
        int len;
 
451
 
 
452
        if (dbus_message_get_args(msg, NULL,
 
453
                                DBUS_TYPE_UINT32, &handle,
 
454
                                DBUS_TYPE_STRING, &record,
 
455
                                DBUS_TYPE_INVALID) == FALSE)
 
456
                return NULL;
 
457
 
 
458
        len = (record ? strlen(record) : 0);
 
459
        if (len == 0)
 
460
                return invalid_arguments(msg);
 
461
 
 
462
        user_record = find_record(serv_adapter, handle,
 
463
                                dbus_message_get_sender(msg));
 
464
        if (!user_record)
 
465
                return g_dbus_create_error(msg,
 
466
                                ERROR_INTERFACE ".NotAvailable",
 
467
                                "Not Available");
 
468
 
 
469
        sdp_record = sdp_xml_parse_record(record, len);
 
470
        if (!sdp_record) {
 
471
                error("Parsing of XML service record failed");
 
472
                sdp_record_free(sdp_record);
 
473
                return g_dbus_create_error(msg,
 
474
                                ERROR_INTERFACE ".Failed",
 
475
                                strerror(EIO));
 
476
        }
 
477
 
 
478
        return update_record(conn, msg, serv_adapter, handle, sdp_record);
 
479
}
 
480
 
 
481
static int remove_record(DBusConnection *conn, const char *sender,
 
482
                        struct service_adapter *serv_adapter,
 
483
                        dbus_uint32_t handle)
 
484
{
 
485
        struct record_data *user_record;
 
486
 
 
487
        debug("remove record 0x%x", handle);
 
488
 
 
489
        user_record = find_record(serv_adapter, handle, sender);
 
490
        if (!user_record)
 
491
                return -1;
 
492
 
 
493
        debug("listner_id %d", user_record->listener_id);
 
494
 
 
495
        g_dbus_remove_watch(conn, user_record->listener_id);
 
496
 
 
497
        exit_callback(user_record);
 
498
 
 
499
        return 0;
 
500
}
 
501
 
 
502
static DBusMessage *add_service_record(DBusConnection *conn,
 
503
                                        DBusMessage *msg, void *data)
 
504
{
 
505
        struct service_adapter *serv_adapter = data;
 
506
        DBusMessage *reply;
 
507
        const char *sender, *record;
 
508
        dbus_uint32_t handle;
 
509
        int err;
 
510
 
 
511
        if (dbus_message_get_args(msg, NULL,
 
512
                        DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE)
 
513
                return NULL;
 
514
 
 
515
        sender = dbus_message_get_sender(msg);
 
516
        err = add_xml_record(conn, sender, serv_adapter, record, &handle);
 
517
        if (err < 0)
 
518
                return failed_strerror(msg, err);
 
519
 
 
520
        reply = dbus_message_new_method_return(msg);
 
521
        if (!reply)
 
522
                return NULL;
 
523
 
 
524
        dbus_message_append_args(reply, DBUS_TYPE_UINT32, &handle,
 
525
                                                        DBUS_TYPE_INVALID);
 
526
 
 
527
        return reply;
 
528
}
 
529
 
 
530
static DBusMessage *update_service_record(DBusConnection *conn,
 
531
                                        DBusMessage *msg, void *data)
 
532
{
 
533
        struct service_adapter *serv_adapter = data;
 
534
 
 
535
        return update_xml_record(conn, msg, serv_adapter);
 
536
}
 
537
 
 
538
static DBusMessage *remove_service_record(DBusConnection *conn,
 
539
                                        DBusMessage *msg, void *data)
 
540
{
 
541
        struct service_adapter *serv_adapter = data;
 
542
        dbus_uint32_t handle;
 
543
        const char *sender;
 
544
 
 
545
        if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
 
546
                                                DBUS_TYPE_INVALID) == FALSE)
 
547
                return NULL;
 
548
 
 
549
        sender = dbus_message_get_sender(msg);
 
550
 
 
551
        if (remove_record(conn, sender, serv_adapter, handle) < 0)
 
552
                return not_available(msg);
 
553
 
 
554
        return dbus_message_new_method_return(msg);
 
555
}
 
556
 
 
557
static void auth_cb(DBusError *derr, void *user_data)
 
558
{
 
559
        struct service_adapter *serv_adapter = user_data;
 
560
        DBusMessage *reply;
 
561
        struct pending_auth *auth;
 
562
        bdaddr_t src;
 
563
 
 
564
        auth = next_pending(serv_adapter);
 
565
        if (auth == NULL) {
 
566
                info("Authorization cancelled: Client exited");
 
567
                return;
 
568
        }
 
569
 
 
570
        if (derr) {
 
571
                adapter_get_address(serv_adapter->adapter, &src);
 
572
                error("Access denied: %s", derr->message);
 
573
 
 
574
                reply = not_authorized(auth->msg);
 
575
                dbus_message_unref(auth->msg);
 
576
                g_dbus_send_message(auth->conn, reply);
 
577
                goto done;
 
578
        }
 
579
 
 
580
        g_dbus_send_reply(auth->conn, auth->msg,
 
581
                        DBUS_TYPE_INVALID);
 
582
 
 
583
done:
 
584
        dbus_connection_unref(auth->conn);
 
585
 
 
586
        serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
 
587
                                                auth);
 
588
        g_free(auth);
 
589
 
 
590
        auth = next_pending(serv_adapter);
 
591
        if (auth == NULL)
 
592
                return;
 
593
 
 
594
        adapter_get_address(serv_adapter->adapter, &src);
 
595
        btd_request_authorization(&src, &auth->dst,
 
596
                                auth->uuid, auth_cb, serv_adapter);
 
597
}
 
598
 
 
599
static DBusMessage *request_authorization(DBusConnection *conn,
 
600
                                                DBusMessage *msg, void *data)
 
601
{
 
602
        struct record_data *user_record;
 
603
        struct service_adapter *serv_adapter = data;
 
604
        struct btd_adapter *adapter = serv_adapter->adapter;
 
605
        sdp_record_t *record;
 
606
        sdp_list_t *services;
 
607
        const char *sender;
 
608
        dbus_uint32_t handle;
 
609
        const char *address;
 
610
        struct pending_auth *auth;
 
611
        char uuid_str[MAX_LEN_UUID_STR];
 
612
        uuid_t *uuid, *uuid128;
 
613
        bdaddr_t src;
 
614
 
 
615
        if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
 
616
                                        DBUS_TYPE_UINT32, &handle,
 
617
                                        DBUS_TYPE_INVALID) == FALSE)
 
618
                return NULL;
 
619
 
 
620
        sender = dbus_message_get_sender(msg);
 
621
        if (find_pending_by_sender(serv_adapter, sender))
 
622
                return failed(msg);
 
623
 
 
624
        user_record = find_record(serv_adapter, handle, sender);
 
625
        if (!user_record)
 
626
                return not_authorized(msg);
 
627
 
 
628
        record = sdp_record_find(user_record->handle);
 
629
 
 
630
        if (sdp_get_service_classes(record, &services) < 0) {
 
631
                sdp_record_free(record);
 
632
                return not_authorized(msg);
 
633
        }
 
634
 
 
635
        if (services == NULL)
 
636
                return not_authorized(msg);
 
637
 
 
638
        uuid = services->data;
 
639
        uuid128 = sdp_uuid_to_uuid128(uuid);
 
640
 
 
641
        sdp_list_free(services, bt_free);
 
642
 
 
643
        if (sdp_uuid2strn(uuid128, uuid_str, MAX_LEN_UUID_STR) < 0) {
 
644
                bt_free(uuid128);
 
645
                return not_authorized(msg);
 
646
        }
 
647
        bt_free(uuid128);
 
648
 
 
649
        auth = g_new0(struct pending_auth, 1);
 
650
        auth->msg = dbus_message_ref(msg);
 
651
        auth->conn = dbus_connection_ref(connection);
 
652
        auth->sender = user_record->sender;
 
653
        memcpy(auth->uuid, uuid_str, MAX_LEN_UUID_STR);
 
654
        str2ba(address, &auth->dst);
 
655
 
 
656
        serv_adapter->pending_list = g_slist_append(serv_adapter->pending_list,
 
657
                        auth);
 
658
 
 
659
        auth = next_pending(serv_adapter);
 
660
        if (auth == NULL)
 
661
                return does_not_exist(msg);
 
662
 
 
663
        adapter_get_address(adapter, &src);
 
664
        if (btd_request_authorization(&src, &auth->dst, auth->uuid, auth_cb,
 
665
                                        serv_adapter) < 0) {
 
666
                serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list, auth);
 
667
                g_free(auth);
 
668
                return not_authorized(msg);
 
669
        }
 
670
 
 
671
        return NULL;
 
672
}
 
673
 
 
674
static DBusMessage *cancel_authorization(DBusConnection *conn,
 
675
                                                DBusMessage *msg, void *data)
 
676
{
 
677
        DBusMessage *reply;
 
678
        struct service_adapter *serv_adapter = data;
 
679
        struct btd_adapter *adapter = serv_adapter->adapter;
 
680
        struct pending_auth *auth;
 
681
        const gchar *sender;
 
682
        bdaddr_t src;
 
683
 
 
684
        sender = dbus_message_get_sender(msg);
 
685
 
 
686
        auth = find_pending_by_sender(serv_adapter, sender);
 
687
        if (auth == NULL)
 
688
                return does_not_exist(msg);
 
689
 
 
690
        adapter_get_address(adapter, &src);
 
691
        btd_cancel_authorization(&src, &auth->dst);
 
692
 
 
693
        reply = not_authorized(auth->msg);
 
694
        dbus_message_unref(auth->msg);
 
695
        g_dbus_send_message(auth->conn, reply);
 
696
 
 
697
        dbus_connection_unref(auth->conn);
 
698
 
 
699
        serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
 
700
                                                auth);
 
701
        g_free(auth);
 
702
 
 
703
        auth = next_pending(serv_adapter);
 
704
        if (auth == NULL)
 
705
                goto done;
 
706
 
 
707
        adapter_get_address(adapter, &src);
 
708
        btd_request_authorization(&src, &auth->dst,
 
709
                                auth->uuid, auth_cb, serv_adapter);
 
710
 
 
711
done:
 
712
        return dbus_message_new_method_return(msg);
 
713
}
 
714
 
 
715
static GDBusMethodTable service_methods[] = {
 
716
        { "AddRecord",          "s",    "u",    add_service_record      },
 
717
        { "UpdateRecord",       "us",   "",     update_service_record   },
 
718
        { "RemoveRecord",       "u",    "",     remove_service_record   },
 
719
        { "RequestAuthorization","su",  "",     request_authorization,
 
720
                                                G_DBUS_METHOD_FLAG_ASYNC},
 
721
        { "CancelAuthorization", "",    "",     cancel_authorization    },
 
722
        { }
 
723
};
 
724
 
 
725
static void path_unregister(void *data)
 
726
{
 
727
        struct service_adapter *serv_adapter = data;
 
728
 
 
729
        g_slist_foreach(serv_adapter->records, (GFunc) exit_callback, NULL);
 
730
}
 
731
 
 
732
static int service_probe(struct btd_adapter *adapter)
 
733
{
 
734
        const char *path = adapter_get_path(adapter);
 
735
        struct service_adapter *serv_adapter;
 
736
 
 
737
        DBG("path %s", path);
 
738
 
 
739
        serv_adapter = g_new0(struct service_adapter, 1);
 
740
        serv_adapter->adapter = adapter;
 
741
        serv_adapter->pending_list = NULL;
 
742
 
 
743
        if (!g_dbus_register_interface(connection, path,
 
744
                                        SERVICE_INTERFACE,
 
745
                                        service_methods, NULL, NULL,
 
746
                                        serv_adapter, path_unregister)) {
 
747
                error("D-Bus failed to register %s interface",
 
748
                                SERVICE_INTERFACE);
 
749
                return -1;
 
750
        }
 
751
 
 
752
        info("Registered interface %s on path %s", SERVICE_INTERFACE, path);
 
753
 
 
754
        return 0;
 
755
}
 
756
 
 
757
static void service_remove(struct btd_adapter *adapter)
 
758
{
 
759
        const char *path = adapter_get_path(adapter);
 
760
 
 
761
        DBG("path %s", path);
 
762
 
 
763
        g_dbus_unregister_interface(connection, path, SERVICE_INTERFACE);
 
764
}
 
765
 
 
766
static struct btd_adapter_driver service_driver = {
 
767
        .name   = "service",
 
768
        .probe  = service_probe,
 
769
        .remove = service_remove,
 
770
};
 
771
 
 
772
static int service_init(void)
 
773
{
 
774
        connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
775
        if (connection == NULL)
 
776
                return -EIO;
 
777
 
 
778
        return btd_register_adapter_driver(&service_driver);
 
779
}
 
780
 
 
781
static void service_exit(void)
 
782
{
 
783
        btd_unregister_adapter_driver(&service_driver);
 
784
 
 
785
        dbus_connection_unref(connection);
 
786
}
 
787
 
 
788
BLUETOOTH_PLUGIN_DEFINE("service", service_init, service_exit)