service.c revision d6334b6272048696a26b3022a9dff6129c41f1ca
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
50static DBusConnection *connection;
51
52struct record_data {
53	uint32_t handle;
54	char *sender;
55	guint listener_id;
56	struct service_adapter *serv_adapter;
57};
58
59struct 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
66struct pending_auth {
67	DBusConnection *conn;
68	DBusMessage *msg;
69	char *sender;
70	bdaddr_t dst;
71	char uuid[MAX_LEN_UUID_STR];
72};
73
74struct service_adapter {
75	struct btd_adapter *adapter;
76	GSList *pending_list;
77	GSList *records;
78};
79
80static 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
91static 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
161static 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
235static GMarkupParser parser = {
236	element_start, element_end, NULL, NULL, NULL
237};
238
239static 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
275static 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
289static 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
301static 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
316static void exit_callback(DBusConnection *conn, 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
340static 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
346static inline DBusMessage *not_available(DBusMessage *msg)
347{
348	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
349							"Not Available");
350}
351
352static inline DBusMessage *failed(DBusMessage *msg)
353{
354	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Failed");
355}
356
357static inline DBusMessage *failed_strerror(DBusMessage *msg, int err)
358{
359	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
360			strerror(err));
361}
362
363static inline DBusMessage *not_authorized(DBusMessage *msg)
364{
365	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized",
366					"Not Authorized");
367}
368
369static inline DBusMessage *does_not_exist(DBusMessage *msg)
370{
371	return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist",
372					"Does Not Exist");
373}
374
375static 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	if (serv_adapter->adapter)
390		adapter_get_address(serv_adapter->adapter, &src);
391	else
392		bacpy(&src, BDADDR_ANY);
393
394	if (add_record_to_server(&src, sdp_record) < 0) {
395		error("Failed to register service record");
396		sdp_record_free(sdp_record);
397		return -EIO;
398	}
399
400	user_record = g_new0(struct record_data, 1);
401	user_record->handle = sdp_record->handle;
402	user_record->sender = g_strdup(sender);
403	user_record->serv_adapter = serv_adapter;
404	user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender,
405					exit_callback, user_record, NULL);
406
407	serv_adapter->records = g_slist_append(serv_adapter->records,
408								user_record);
409
410	debug("listener_id %d", user_record->listener_id);
411
412	*handle = user_record->handle;
413
414	return 0;
415}
416
417static DBusMessage *update_record(DBusConnection *conn, DBusMessage *msg,
418		struct service_adapter *serv_adapter,
419		dbus_uint32_t handle, sdp_record_t *sdp_record)
420{
421	bdaddr_t src;
422	int err;
423
424	if (remove_record_from_server(handle) < 0) {
425		sdp_record_free(sdp_record);
426		return g_dbus_create_error(msg,
427				ERROR_INTERFACE ".NotAvailable",
428				"Not Available");
429	}
430
431	if (serv_adapter->adapter)
432		adapter_get_address(serv_adapter->adapter, &src);
433	else
434		bacpy(&src, BDADDR_ANY);
435
436	sdp_record->handle = handle;
437	err = add_record_to_server(&src, sdp_record);
438	if (err < 0) {
439		sdp_record_free(sdp_record);
440		error("Failed to update the service record");
441		return g_dbus_create_error(msg,
442				ERROR_INTERFACE ".Failed",
443				strerror(EIO));
444	}
445
446	return dbus_message_new_method_return(msg);
447}
448
449static DBusMessage *update_xml_record(DBusConnection *conn,
450				DBusMessage *msg,
451				struct service_adapter *serv_adapter)
452{
453	struct record_data *user_record;
454	sdp_record_t *sdp_record;
455	const char *record;
456	dbus_uint32_t handle;
457	int len;
458
459	if (dbus_message_get_args(msg, NULL,
460				DBUS_TYPE_UINT32, &handle,
461				DBUS_TYPE_STRING, &record,
462				DBUS_TYPE_INVALID) == FALSE)
463		return NULL;
464
465	len = (record ? strlen(record) : 0);
466	if (len == 0)
467		return invalid_arguments(msg);
468
469	user_record = find_record(serv_adapter, handle,
470				dbus_message_get_sender(msg));
471	if (!user_record)
472		return g_dbus_create_error(msg,
473				ERROR_INTERFACE ".NotAvailable",
474				"Not Available");
475
476	sdp_record = sdp_xml_parse_record(record, len);
477	if (!sdp_record) {
478		error("Parsing of XML service record failed");
479		sdp_record_free(sdp_record);
480		return g_dbus_create_error(msg,
481				ERROR_INTERFACE ".Failed",
482				strerror(EIO));
483	}
484
485	return update_record(conn, msg, serv_adapter, handle, sdp_record);
486}
487
488static int remove_record(DBusConnection *conn, const char *sender,
489			struct service_adapter *serv_adapter,
490			dbus_uint32_t handle)
491{
492	struct record_data *user_record;
493
494	debug("remove record 0x%x", handle);
495
496	user_record = find_record(serv_adapter, handle, sender);
497	if (!user_record)
498		return -1;
499
500	debug("listner_id %d", user_record->listener_id);
501
502	g_dbus_remove_watch(conn, user_record->listener_id);
503
504	exit_callback(conn, user_record);
505
506	return 0;
507}
508
509static DBusMessage *add_service_record(DBusConnection *conn,
510					DBusMessage *msg, void *data)
511{
512	struct service_adapter *serv_adapter = data;
513	DBusMessage *reply;
514	const char *sender, *record;
515	dbus_uint32_t handle;
516	int err;
517
518	if (dbus_message_get_args(msg, NULL,
519			DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE)
520		return NULL;
521
522	sender = dbus_message_get_sender(msg);
523	err = add_xml_record(conn, sender, serv_adapter, record, &handle);
524	if (err < 0)
525		return failed_strerror(msg, err);
526
527	reply = dbus_message_new_method_return(msg);
528	if (!reply)
529		return NULL;
530
531	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &handle,
532							DBUS_TYPE_INVALID);
533
534	return reply;
535}
536
537static DBusMessage *update_service_record(DBusConnection *conn,
538					DBusMessage *msg, void *data)
539{
540	struct service_adapter *serv_adapter = data;
541
542	return update_xml_record(conn, msg, serv_adapter);
543}
544
545static DBusMessage *remove_service_record(DBusConnection *conn,
546					DBusMessage *msg, void *data)
547{
548	struct service_adapter *serv_adapter = data;
549	dbus_uint32_t handle;
550	const char *sender;
551
552	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
553						DBUS_TYPE_INVALID) == FALSE)
554		return NULL;
555
556	sender = dbus_message_get_sender(msg);
557
558	if (remove_record(conn, sender, serv_adapter, handle) < 0)
559		return not_available(msg);
560
561	return dbus_message_new_method_return(msg);
562}
563
564static void auth_cb(DBusError *derr, void *user_data)
565{
566	struct service_adapter *serv_adapter = user_data;
567	DBusMessage *reply;
568	struct pending_auth *auth;
569	bdaddr_t src;
570
571	auth = next_pending(serv_adapter);
572	if (auth == NULL) {
573		info("Authorization cancelled: Client exited");
574		return;
575	}
576
577	if (derr) {
578		adapter_get_address(serv_adapter->adapter, &src);
579		error("Access denied: %s", derr->message);
580
581		reply = not_authorized(auth->msg);
582		dbus_message_unref(auth->msg);
583		g_dbus_send_message(auth->conn, reply);
584		goto done;
585	}
586
587	g_dbus_send_reply(auth->conn, auth->msg,
588			DBUS_TYPE_INVALID);
589
590done:
591	dbus_connection_unref(auth->conn);
592
593	serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
594									auth);
595	g_free(auth);
596
597	auth = next_pending(serv_adapter);
598	if (auth == NULL)
599		return;
600
601	if (serv_adapter->adapter)
602		adapter_get_address(serv_adapter->adapter, &src);
603	else
604		bacpy(&src, BDADDR_ANY);
605
606	btd_request_authorization(&src, &auth->dst,
607					auth->uuid, auth_cb, serv_adapter);
608}
609
610static DBusMessage *request_authorization(DBusConnection *conn,
611						DBusMessage *msg, void *data)
612{
613	struct record_data *user_record;
614	struct service_adapter *serv_adapter = data;
615	sdp_record_t *record;
616	sdp_list_t *services;
617	const char *sender;
618	dbus_uint32_t handle;
619	const char *address;
620	struct pending_auth *auth;
621	char uuid_str[MAX_LEN_UUID_STR];
622	uuid_t *uuid, *uuid128;
623	bdaddr_t src;
624
625	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
626					DBUS_TYPE_UINT32, &handle,
627					DBUS_TYPE_INVALID) == FALSE)
628		return NULL;
629
630	sender = dbus_message_get_sender(msg);
631	if (find_pending_by_sender(serv_adapter, sender))
632		return failed(msg);
633
634	user_record = find_record(serv_adapter, handle, sender);
635	if (!user_record)
636		return not_authorized(msg);
637
638	record = sdp_record_find(user_record->handle);
639
640	if (sdp_get_service_classes(record, &services) < 0) {
641		sdp_record_free(record);
642		return not_authorized(msg);
643	}
644
645	if (services == NULL)
646		return not_authorized(msg);
647
648	uuid = services->data;
649	uuid128 = sdp_uuid_to_uuid128(uuid);
650
651	sdp_list_free(services, bt_free);
652
653	if (sdp_uuid2strn(uuid128, uuid_str, MAX_LEN_UUID_STR) < 0) {
654		bt_free(uuid128);
655		return not_authorized(msg);
656	}
657	bt_free(uuid128);
658
659	auth = g_new0(struct pending_auth, 1);
660	auth->msg = dbus_message_ref(msg);
661	auth->conn = dbus_connection_ref(connection);
662	auth->sender = user_record->sender;
663	memcpy(auth->uuid, uuid_str, MAX_LEN_UUID_STR);
664	str2ba(address, &auth->dst);
665
666	serv_adapter->pending_list = g_slist_append(serv_adapter->pending_list,
667									auth);
668
669	auth = next_pending(serv_adapter);
670	if (auth == NULL)
671		return does_not_exist(msg);
672
673	if (serv_adapter->adapter)
674		adapter_get_address(serv_adapter->adapter, &src);
675	else
676		bacpy(&src, BDADDR_ANY);
677
678	if (btd_request_authorization(&src, &auth->dst, auth->uuid, auth_cb,
679							serv_adapter) < 0) {
680		serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
681									auth);
682		g_free(auth);
683		return not_authorized(msg);
684	}
685
686	return NULL;
687}
688
689static DBusMessage *cancel_authorization(DBusConnection *conn,
690						DBusMessage *msg, void *data)
691{
692	DBusMessage *reply;
693	struct service_adapter *serv_adapter = data;
694	struct pending_auth *auth;
695	const gchar *sender;
696	bdaddr_t src;
697
698	sender = dbus_message_get_sender(msg);
699
700	auth = find_pending_by_sender(serv_adapter, sender);
701	if (auth == NULL)
702		return does_not_exist(msg);
703
704	if (serv_adapter->adapter)
705		adapter_get_address(serv_adapter->adapter, &src);
706	else
707		bacpy(&src, BDADDR_ANY);
708
709	btd_cancel_authorization(&src, &auth->dst);
710
711	reply = not_authorized(auth->msg);
712	dbus_message_unref(auth->msg);
713	g_dbus_send_message(auth->conn, reply);
714
715	dbus_connection_unref(auth->conn);
716
717	serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
718									auth);
719	g_free(auth);
720
721	auth = next_pending(serv_adapter);
722	if (auth == NULL)
723		goto done;
724
725	if (serv_adapter->adapter)
726		adapter_get_address(serv_adapter->adapter, &src);
727	else
728		bacpy(&src, BDADDR_ANY);
729
730	btd_request_authorization(&src, &auth->dst,
731					auth->uuid, auth_cb, serv_adapter);
732
733done:
734	return dbus_message_new_method_return(msg);
735}
736
737static GDBusMethodTable service_methods[] = {
738	{ "AddRecord",		"s",	"u",	add_service_record	},
739	{ "UpdateRecord",	"us",	"",	update_service_record	},
740	{ "RemoveRecord",	"u",	"",	remove_service_record	},
741	{ "RequestAuthorization","su",	"",	request_authorization,
742						G_DBUS_METHOD_FLAG_ASYNC},
743	{ "CancelAuthorization", "",	"",	cancel_authorization	},
744	{ }
745};
746
747static void path_unregister(void *data)
748{
749	struct service_adapter *serv_adapter = data;
750	GSList *l, *next = NULL;
751
752	for (l = serv_adapter->records; l != NULL; l = next) {
753		struct record_data *user_record = l->data;
754
755		next = l->next;
756
757		g_dbus_remove_watch(connection, user_record->listener_id);
758		exit_callback(connection, user_record);
759	}
760}
761
762static int register_interface(const char *path, struct btd_adapter *adapter)
763{
764	struct service_adapter *serv_adapter;
765
766	DBG("path %s", path);
767
768	serv_adapter = g_try_new0(struct service_adapter, 1);
769	if (serv_adapter == NULL)
770		return -ENOMEM;
771
772	serv_adapter->adapter = adapter;
773	serv_adapter->pending_list = NULL;
774
775	if (g_dbus_register_interface(connection, path, SERVICE_INTERFACE,
776				service_methods, NULL, NULL, serv_adapter,
777						path_unregister) == FALSE) {
778		error("D-Bus failed to register %s interface",
779							SERVICE_INTERFACE);
780		g_free(serv_adapter);
781		return -EIO;
782	}
783
784	info("Registered interface %s on path %s", SERVICE_INTERFACE, path);
785
786	return 0;
787}
788
789static void unregister_interface(const char *path)
790{
791	DBG("path %s", path);
792
793	g_dbus_unregister_interface(connection, path, SERVICE_INTERFACE);
794}
795
796static int service_probe(struct btd_adapter *adapter)
797{
798	register_interface(adapter_get_path(adapter), adapter);
799
800	return 0;
801}
802
803static void service_remove(struct btd_adapter *adapter)
804{
805	unregister_interface(adapter_get_path(adapter));
806}
807
808static struct btd_adapter_driver service_driver = {
809	.name	= "service",
810	.probe	= service_probe,
811	.remove	= service_remove,
812};
813
814static const char *any_path;
815
816static int service_init(void)
817{
818	int err;
819
820	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
821	if (connection == NULL)
822		return -EIO;
823
824	any_path = btd_adapter_any_request_path();
825	if (any_path != NULL) {
826		if (register_interface(any_path, NULL) < 0) {
827			btd_adapter_any_release_path();
828			any_path = NULL;
829		}
830	}
831
832	err = btd_register_adapter_driver(&service_driver);
833	if (err < 0) {
834		dbus_connection_unref(connection);
835		return err;
836	}
837
838	return 0;
839}
840
841static void service_exit(void)
842{
843	btd_unregister_adapter_driver(&service_driver);
844
845	if (any_path != NULL) {
846		unregister_interface(any_path);
847
848		btd_adapter_any_release_path();
849		any_path = NULL;
850	}
851
852	dbus_connection_unref(connection);
853}
854
855BLUETOOTH_PLUGIN_DEFINE("service", service_init, service_exit)
856