service.c revision 20ccc578c85111ca8790bd773b6fa337e80b4c71
11591693c7b415e9869157c711fe11263c95d74eDavid Li/*
21591693c7b415e9869157c711fe11263c95d74eDavid Li *
31591693c7b415e9869157c711fe11263c95d74eDavid Li *  BlueZ - Bluetooth protocol stack for Linux
41591693c7b415e9869157c711fe11263c95d74eDavid Li *
51591693c7b415e9869157c711fe11263c95d74eDavid Li *  Copyright (C) 2006-2010  Nokia Corporation
61591693c7b415e9869157c711fe11263c95d74eDavid Li *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
71591693c7b415e9869157c711fe11263c95d74eDavid Li *
81591693c7b415e9869157c711fe11263c95d74eDavid Li *
91591693c7b415e9869157c711fe11263c95d74eDavid Li *  This program is free software; you can redistribute it and/or modify
101591693c7b415e9869157c711fe11263c95d74eDavid Li *  it under the terms of the GNU General Public License as published by
111591693c7b415e9869157c711fe11263c95d74eDavid Li *  the Free Software Foundation; either version 2 of the License, or
121591693c7b415e9869157c711fe11263c95d74eDavid Li *  (at your option) any later version.
131591693c7b415e9869157c711fe11263c95d74eDavid Li *
141591693c7b415e9869157c711fe11263c95d74eDavid Li *  This program is distributed in the hope that it will be useful,
151591693c7b415e9869157c711fe11263c95d74eDavid Li *  but WITHOUT ANY WARRANTY; without even the implied warranty of
161591693c7b415e9869157c711fe11263c95d74eDavid Li *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
171591693c7b415e9869157c711fe11263c95d74eDavid Li *  GNU General Public License for more details.
181591693c7b415e9869157c711fe11263c95d74eDavid Li *
191591693c7b415e9869157c711fe11263c95d74eDavid Li *  You should have received a copy of the GNU General Public License
201591693c7b415e9869157c711fe11263c95d74eDavid Li *  along with this program; if not, write to the Free Software
211591693c7b415e9869157c711fe11263c95d74eDavid Li *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
221591693c7b415e9869157c711fe11263c95d74eDavid Li *
231591693c7b415e9869157c711fe11263c95d74eDavid Li */
241591693c7b415e9869157c711fe11263c95d74eDavid Li
251591693c7b415e9869157c711fe11263c95d74eDavid Li#ifdef HAVE_CONFIG_H
261591693c7b415e9869157c711fe11263c95d74eDavid Li#include <config.h>
271591693c7b415e9869157c711fe11263c95d74eDavid Li#endif
281591693c7b415e9869157c711fe11263c95d74eDavid Li
291591693c7b415e9869157c711fe11263c95d74eDavid Li#include <errno.h>
301591693c7b415e9869157c711fe11263c95d74eDavid Li#include <stdlib.h>
311591693c7b415e9869157c711fe11263c95d74eDavid Li#include <string.h>
321591693c7b415e9869157c711fe11263c95d74eDavid Li
331591693c7b415e9869157c711fe11263c95d74eDavid Li#include <bluetooth/bluetooth.h>
341591693c7b415e9869157c711fe11263c95d74eDavid Li#include <bluetooth/sdp.h>
351591693c7b415e9869157c711fe11263c95d74eDavid Li#include <bluetooth/sdp_lib.h>
361591693c7b415e9869157c711fe11263c95d74eDavid Li
371591693c7b415e9869157c711fe11263c95d74eDavid Li#include <gdbus.h>
381591693c7b415e9869157c711fe11263c95d74eDavid Li
391591693c7b415e9869157c711fe11263c95d74eDavid Li#include "sdpd.h"
401591693c7b415e9869157c711fe11263c95d74eDavid Li#include "sdp-xml.h"
411591693c7b415e9869157c711fe11263c95d74eDavid Li#include "plugin.h"
421591693c7b415e9869157c711fe11263c95d74eDavid Li#include "adapter.h"
431591693c7b415e9869157c711fe11263c95d74eDavid Li#include "error.h"
441591693c7b415e9869157c711fe11263c95d74eDavid Li#include "log.h"
451591693c7b415e9869157c711fe11263c95d74eDavid Li
461591693c7b415e9869157c711fe11263c95d74eDavid Li#define SERVICE_INTERFACE "org.bluez.Service"
471591693c7b415e9869157c711fe11263c95d74eDavid Li
481591693c7b415e9869157c711fe11263c95d74eDavid Listatic DBusConnection *connection;
491591693c7b415e9869157c711fe11263c95d74eDavid Li
501591693c7b415e9869157c711fe11263c95d74eDavid Listruct record_data {
511591693c7b415e9869157c711fe11263c95d74eDavid Li	uint32_t handle;
521591693c7b415e9869157c711fe11263c95d74eDavid Li	char *sender;
531591693c7b415e9869157c711fe11263c95d74eDavid Li	guint listener_id;
541591693c7b415e9869157c711fe11263c95d74eDavid Li	struct service_adapter *serv_adapter;
551591693c7b415e9869157c711fe11263c95d74eDavid Li};
561591693c7b415e9869157c711fe11263c95d74eDavid Li
571591693c7b415e9869157c711fe11263c95d74eDavid Listruct context_data {
581591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_record_t *record;
591591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_data_t attr_data;
601591693c7b415e9869157c711fe11263c95d74eDavid Li	struct sdp_xml_data *stack_head;
611591693c7b415e9869157c711fe11263c95d74eDavid Li	uint16_t attr_id;
621591693c7b415e9869157c711fe11263c95d74eDavid Li};
631591693c7b415e9869157c711fe11263c95d74eDavid Li
641591693c7b415e9869157c711fe11263c95d74eDavid Listruct pending_auth {
651591693c7b415e9869157c711fe11263c95d74eDavid Li	DBusConnection *conn;
661591693c7b415e9869157c711fe11263c95d74eDavid Li	DBusMessage *msg;
671591693c7b415e9869157c711fe11263c95d74eDavid Li	char *sender;
681591693c7b415e9869157c711fe11263c95d74eDavid Li	bdaddr_t dst;
691591693c7b415e9869157c711fe11263c95d74eDavid Li	char uuid[MAX_LEN_UUID_STR];
701591693c7b415e9869157c711fe11263c95d74eDavid Li};
71c0025eb1a3d421c0355a21db9d8ea2bd81278460David Li
72c0025eb1a3d421c0355a21db9d8ea2bd81278460David Listruct service_adapter {
731591693c7b415e9869157c711fe11263c95d74eDavid Li	struct btd_adapter *adapter;
74d50d9a90a0df4d706421850e17c0fbd85bf710eeDavid Li	GSList *pending_list;
751591693c7b415e9869157c711fe11263c95d74eDavid Li	GSList *records;
761591693c7b415e9869157c711fe11263c95d74eDavid Li};
771591693c7b415e9869157c711fe11263c95d74eDavid Li
781591693c7b415e9869157c711fe11263c95d74eDavid Listatic struct service_adapter *serv_adapter_any = NULL;
791591693c7b415e9869157c711fe11263c95d74eDavid Li
801591693c7b415e9869157c711fe11263c95d74eDavid Listatic int compute_seq_size(sdp_data_t *data)
811591693c7b415e9869157c711fe11263c95d74eDavid Li{
821591693c7b415e9869157c711fe11263c95d74eDavid Li	int unit_size = data->unitSize;
831591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_data_t *seq = data->val.dataseq;
841591693c7b415e9869157c711fe11263c95d74eDavid Li
851591693c7b415e9869157c711fe11263c95d74eDavid Li	for (; seq; seq = seq->next)
861591693c7b415e9869157c711fe11263c95d74eDavid Li		unit_size += seq->unitSize;
871591693c7b415e9869157c711fe11263c95d74eDavid Li
881591693c7b415e9869157c711fe11263c95d74eDavid Li	return unit_size;
891591693c7b415e9869157c711fe11263c95d74eDavid Li}
901591693c7b415e9869157c711fe11263c95d74eDavid Li
911591693c7b415e9869157c711fe11263c95d74eDavid Listatic void element_start(GMarkupParseContext *context,
921591693c7b415e9869157c711fe11263c95d74eDavid Li		const gchar *element_name, const gchar **attribute_names,
931591693c7b415e9869157c711fe11263c95d74eDavid Li		const gchar **attribute_values, gpointer user_data, GError **err)
941591693c7b415e9869157c711fe11263c95d74eDavid Li{
951591693c7b415e9869157c711fe11263c95d74eDavid Li	struct context_data *ctx_data = user_data;
961591693c7b415e9869157c711fe11263c95d74eDavid Li
971591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!strcmp(element_name, "record"))
981591693c7b415e9869157c711fe11263c95d74eDavid Li		return;
991591693c7b415e9869157c711fe11263c95d74eDavid Li
1001591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!strcmp(element_name, "attribute")) {
1011591693c7b415e9869157c711fe11263c95d74eDavid Li		int i;
1021591693c7b415e9869157c711fe11263c95d74eDavid Li		for (i = 0; attribute_names[i]; i++) {
1031591693c7b415e9869157c711fe11263c95d74eDavid Li			if (!strcmp(attribute_names[i], "id")) {
1041591693c7b415e9869157c711fe11263c95d74eDavid Li				ctx_data->attr_id = strtol(attribute_values[i], 0, 0);
1051591693c7b415e9869157c711fe11263c95d74eDavid Li				break;
1061591693c7b415e9869157c711fe11263c95d74eDavid Li			}
1071591693c7b415e9869157c711fe11263c95d74eDavid Li		}
1081591693c7b415e9869157c711fe11263c95d74eDavid Li		DBG("New attribute 0x%04x", ctx_data->attr_id);
1091591693c7b415e9869157c711fe11263c95d74eDavid Li		return;
1101591693c7b415e9869157c711fe11263c95d74eDavid Li	}
1111591693c7b415e9869157c711fe11263c95d74eDavid Li
1121591693c7b415e9869157c711fe11263c95d74eDavid Li	if (ctx_data->stack_head) {
1131591693c7b415e9869157c711fe11263c95d74eDavid Li		struct sdp_xml_data *newelem = sdp_xml_data_alloc();
1141591693c7b415e9869157c711fe11263c95d74eDavid Li		newelem->next = ctx_data->stack_head;
1151591693c7b415e9869157c711fe11263c95d74eDavid Li		ctx_data->stack_head = newelem;
1161591693c7b415e9869157c711fe11263c95d74eDavid Li	} else {
1171591693c7b415e9869157c711fe11263c95d74eDavid Li		ctx_data->stack_head = sdp_xml_data_alloc();
1181591693c7b415e9869157c711fe11263c95d74eDavid Li		ctx_data->stack_head->next = NULL;
1191591693c7b415e9869157c711fe11263c95d74eDavid Li	}
1201591693c7b415e9869157c711fe11263c95d74eDavid Li
1211591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!strcmp(element_name, "sequence"))
1221591693c7b415e9869157c711fe11263c95d74eDavid Li		ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
1231591693c7b415e9869157c711fe11263c95d74eDavid Li	else if (!strcmp(element_name, "alternate"))
1241591693c7b415e9869157c711fe11263c95d74eDavid Li		ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
1251591693c7b415e9869157c711fe11263c95d74eDavid Li	else {
1261591693c7b415e9869157c711fe11263c95d74eDavid Li		int i;
1271591693c7b415e9869157c711fe11263c95d74eDavid Li		/* Parse value, name, encoding */
1281591693c7b415e9869157c711fe11263c95d74eDavid Li		for (i = 0; attribute_names[i]; i++) {
1291591693c7b415e9869157c711fe11263c95d74eDavid Li			if (!strcmp(attribute_names[i], "value")) {
1301591693c7b415e9869157c711fe11263c95d74eDavid Li				int curlen = strlen(ctx_data->stack_head->text);
1311591693c7b415e9869157c711fe11263c95d74eDavid Li				int attrlen = strlen(attribute_values[i]);
1321591693c7b415e9869157c711fe11263c95d74eDavid Li
1331591693c7b415e9869157c711fe11263c95d74eDavid Li				/* Ensure we're big enough */
1341591693c7b415e9869157c711fe11263c95d74eDavid Li				while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) {
1351591693c7b415e9869157c711fe11263c95d74eDavid Li					sdp_xml_data_expand(ctx_data->stack_head);
1361591693c7b415e9869157c711fe11263c95d74eDavid Li				}
1371591693c7b415e9869157c711fe11263c95d74eDavid Li
1381591693c7b415e9869157c711fe11263c95d74eDavid Li				memcpy(ctx_data->stack_head->text + curlen,
1391591693c7b415e9869157c711fe11263c95d74eDavid Li						attribute_values[i], attrlen);
1401591693c7b415e9869157c711fe11263c95d74eDavid Li				ctx_data->stack_head->text[curlen + attrlen] = '\0';
1411591693c7b415e9869157c711fe11263c95d74eDavid Li			}
1421591693c7b415e9869157c711fe11263c95d74eDavid Li
1431591693c7b415e9869157c711fe11263c95d74eDavid Li			if (!strcmp(attribute_names[i], "encoding")) {
1441591693c7b415e9869157c711fe11263c95d74eDavid Li				if (!strcmp(attribute_values[i], "hex"))
1451591693c7b415e9869157c711fe11263c95d74eDavid Li					ctx_data->stack_head->type = 1;
1461591693c7b415e9869157c711fe11263c95d74eDavid Li			}
1471591693c7b415e9869157c711fe11263c95d74eDavid Li
1481591693c7b415e9869157c711fe11263c95d74eDavid Li			if (!strcmp(attribute_names[i], "name")) {
1491591693c7b415e9869157c711fe11263c95d74eDavid Li				ctx_data->stack_head->name = strdup(attribute_values[i]);
1501591693c7b415e9869157c711fe11263c95d74eDavid Li			}
1511591693c7b415e9869157c711fe11263c95d74eDavid Li		}
1521591693c7b415e9869157c711fe11263c95d74eDavid Li
1531591693c7b415e9869157c711fe11263c95d74eDavid Li		ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
1541591693c7b415e9869157c711fe11263c95d74eDavid Li				ctx_data->stack_head, ctx_data->record);
1551591693c7b415e9869157c711fe11263c95d74eDavid Li
1561591693c7b415e9869157c711fe11263c95d74eDavid Li		if (ctx_data->stack_head->data == NULL)
1571591693c7b415e9869157c711fe11263c95d74eDavid Li			error("Can't parse element %s", element_name);
1581591693c7b415e9869157c711fe11263c95d74eDavid Li	}
1591591693c7b415e9869157c711fe11263c95d74eDavid Li}
1601591693c7b415e9869157c711fe11263c95d74eDavid Li
1611591693c7b415e9869157c711fe11263c95d74eDavid Listatic void element_end(GMarkupParseContext *context,
1621591693c7b415e9869157c711fe11263c95d74eDavid Li		const gchar *element_name, gpointer user_data, GError **err)
1631591693c7b415e9869157c711fe11263c95d74eDavid Li{
1641591693c7b415e9869157c711fe11263c95d74eDavid Li	struct context_data *ctx_data = user_data;
1651591693c7b415e9869157c711fe11263c95d74eDavid Li	struct sdp_xml_data *elem;
1661591693c7b415e9869157c711fe11263c95d74eDavid Li
1671591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!strcmp(element_name, "record"))
1681591693c7b415e9869157c711fe11263c95d74eDavid Li		return;
1691591693c7b415e9869157c711fe11263c95d74eDavid Li
1701591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!strcmp(element_name, "attribute")) {
1711591693c7b415e9869157c711fe11263c95d74eDavid Li		if (ctx_data->stack_head && ctx_data->stack_head->data) {
1721591693c7b415e9869157c711fe11263c95d74eDavid Li			int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
1731591693c7b415e9869157c711fe11263c95d74eDavid Li							ctx_data->stack_head->data);
1741591693c7b415e9869157c711fe11263c95d74eDavid Li			if (ret == -1)
1751591693c7b415e9869157c711fe11263c95d74eDavid Li				DBG("Trouble adding attribute\n");
1761591693c7b415e9869157c711fe11263c95d74eDavid Li
1771591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data = NULL;
1781591693c7b415e9869157c711fe11263c95d74eDavid Li			sdp_xml_data_free(ctx_data->stack_head);
1791591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head = NULL;
1801591693c7b415e9869157c711fe11263c95d74eDavid Li		} else {
181d50d9a90a0df4d706421850e17c0fbd85bf710eeDavid Li			DBG("No data for attribute 0x%04x\n", ctx_data->attr_id);
1821591693c7b415e9869157c711fe11263c95d74eDavid Li		}
183d50d9a90a0df4d706421850e17c0fbd85bf710eeDavid Li		return;
1841591693c7b415e9869157c711fe11263c95d74eDavid Li	}
1851591693c7b415e9869157c711fe11263c95d74eDavid Li
1861591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!strcmp(element_name, "sequence")) {
1871591693c7b415e9869157c711fe11263c95d74eDavid Li		ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
1881591693c7b415e9869157c711fe11263c95d74eDavid Li
1891591693c7b415e9869157c711fe11263c95d74eDavid Li		if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
1901591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
1911591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data->dtd = SDP_SEQ32;
1921591693c7b415e9869157c711fe11263c95d74eDavid Li		} else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
1931591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
1941591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data->dtd = SDP_SEQ16;
1951591693c7b415e9869157c711fe11263c95d74eDavid Li		} else {
1961591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
1971591693c7b415e9869157c711fe11263c95d74eDavid Li		}
1981591693c7b415e9869157c711fe11263c95d74eDavid Li	} else if (!strcmp(element_name, "alternate")) {
1991591693c7b415e9869157c711fe11263c95d74eDavid Li		ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
2001591693c7b415e9869157c711fe11263c95d74eDavid Li
2011591693c7b415e9869157c711fe11263c95d74eDavid Li		if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
2021591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
2031591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data->dtd = SDP_ALT32;
2041591693c7b415e9869157c711fe11263c95d74eDavid Li		} else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
2051591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
2061591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data->dtd = SDP_ALT16;
2071591693c7b415e9869157c711fe11263c95d74eDavid Li		} else {
2081591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
2091591693c7b415e9869157c711fe11263c95d74eDavid Li		}
2101591693c7b415e9869157c711fe11263c95d74eDavid Li	}
2111591693c7b415e9869157c711fe11263c95d74eDavid Li
2121591693c7b415e9869157c711fe11263c95d74eDavid Li	if (ctx_data->stack_head->next && ctx_data->stack_head->data &&
2131591693c7b415e9869157c711fe11263c95d74eDavid Li					ctx_data->stack_head->next->data) {
2141591693c7b415e9869157c711fe11263c95d74eDavid Li		switch (ctx_data->stack_head->next->data->dtd) {
2151591693c7b415e9869157c711fe11263c95d74eDavid Li		case SDP_SEQ8:
2161591693c7b415e9869157c711fe11263c95d74eDavid Li		case SDP_SEQ16:
2171591693c7b415e9869157c711fe11263c95d74eDavid Li		case SDP_SEQ32:
2181591693c7b415e9869157c711fe11263c95d74eDavid Li		case SDP_ALT8:
2191591693c7b415e9869157c711fe11263c95d74eDavid Li		case SDP_ALT16:
2201591693c7b415e9869157c711fe11263c95d74eDavid Li		case SDP_ALT32:
2211591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->next->data->val.dataseq =
2221591693c7b415e9869157c711fe11263c95d74eDavid Li				sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq,
2231591693c7b415e9869157c711fe11263c95d74eDavid Li								ctx_data->stack_head->data);
2241591693c7b415e9869157c711fe11263c95d74eDavid Li			ctx_data->stack_head->data = NULL;
2251591693c7b415e9869157c711fe11263c95d74eDavid Li			break;
2261591693c7b415e9869157c711fe11263c95d74eDavid Li		}
2271591693c7b415e9869157c711fe11263c95d74eDavid Li
2281591693c7b415e9869157c711fe11263c95d74eDavid Li		elem = ctx_data->stack_head;
2291591693c7b415e9869157c711fe11263c95d74eDavid Li		ctx_data->stack_head = ctx_data->stack_head->next;
2301591693c7b415e9869157c711fe11263c95d74eDavid Li
2311591693c7b415e9869157c711fe11263c95d74eDavid Li		sdp_xml_data_free(elem);
2321591693c7b415e9869157c711fe11263c95d74eDavid Li	}
2331591693c7b415e9869157c711fe11263c95d74eDavid Li}
2341591693c7b415e9869157c711fe11263c95d74eDavid Li
2351591693c7b415e9869157c711fe11263c95d74eDavid Listatic GMarkupParser parser = {
2361591693c7b415e9869157c711fe11263c95d74eDavid Li	element_start, element_end, NULL, NULL, NULL
2371591693c7b415e9869157c711fe11263c95d74eDavid Li};
2381591693c7b415e9869157c711fe11263c95d74eDavid Li
2391591693c7b415e9869157c711fe11263c95d74eDavid Listatic sdp_record_t *sdp_xml_parse_record(const char *data, int size)
2401591693c7b415e9869157c711fe11263c95d74eDavid Li{
2411591693c7b415e9869157c711fe11263c95d74eDavid Li	GMarkupParseContext *ctx;
2421591693c7b415e9869157c711fe11263c95d74eDavid Li	struct context_data *ctx_data;
2431591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_record_t *record;
2441591693c7b415e9869157c711fe11263c95d74eDavid Li
2451591693c7b415e9869157c711fe11263c95d74eDavid Li	ctx_data = malloc(sizeof(*ctx_data));
2461591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!ctx_data)
2471591693c7b415e9869157c711fe11263c95d74eDavid Li		return NULL;
2481591693c7b415e9869157c711fe11263c95d74eDavid Li
2491591693c7b415e9869157c711fe11263c95d74eDavid Li	record = sdp_record_alloc();
2501591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!record) {
2511591693c7b415e9869157c711fe11263c95d74eDavid Li		free(ctx_data);
2521591693c7b415e9869157c711fe11263c95d74eDavid Li		return NULL;
2531591693c7b415e9869157c711fe11263c95d74eDavid Li	}
2541591693c7b415e9869157c711fe11263c95d74eDavid Li
2551591693c7b415e9869157c711fe11263c95d74eDavid Li	memset(ctx_data, 0, sizeof(*ctx_data));
2561591693c7b415e9869157c711fe11263c95d74eDavid Li	ctx_data->record = record;
2571591693c7b415e9869157c711fe11263c95d74eDavid Li
2581591693c7b415e9869157c711fe11263c95d74eDavid Li	ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
2591591693c7b415e9869157c711fe11263c95d74eDavid Li
2601591693c7b415e9869157c711fe11263c95d74eDavid Li	if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
2611591693c7b415e9869157c711fe11263c95d74eDavid Li		error("XML parsing error");
2621591693c7b415e9869157c711fe11263c95d74eDavid Li		g_markup_parse_context_free(ctx);
2631591693c7b415e9869157c711fe11263c95d74eDavid Li		sdp_record_free(record);
2641591693c7b415e9869157c711fe11263c95d74eDavid Li		free(ctx_data);
2651591693c7b415e9869157c711fe11263c95d74eDavid Li		return NULL;
2661591693c7b415e9869157c711fe11263c95d74eDavid Li	}
2671591693c7b415e9869157c711fe11263c95d74eDavid Li
2681591693c7b415e9869157c711fe11263c95d74eDavid Li	g_markup_parse_context_free(ctx);
2691591693c7b415e9869157c711fe11263c95d74eDavid Li
2701591693c7b415e9869157c711fe11263c95d74eDavid Li	free(ctx_data);
2711591693c7b415e9869157c711fe11263c95d74eDavid Li
2721591693c7b415e9869157c711fe11263c95d74eDavid Li	return record;
2731591693c7b415e9869157c711fe11263c95d74eDavid Li}
2741591693c7b415e9869157c711fe11263c95d74eDavid Li
2751591693c7b415e9869157c711fe11263c95d74eDavid Listatic struct record_data *find_record(struct service_adapter *serv_adapter,
2761591693c7b415e9869157c711fe11263c95d74eDavid Li					uint32_t handle, const char *sender)
2771591693c7b415e9869157c711fe11263c95d74eDavid Li{
2781591693c7b415e9869157c711fe11263c95d74eDavid Li	GSList *list;
2791591693c7b415e9869157c711fe11263c95d74eDavid Li
2801591693c7b415e9869157c711fe11263c95d74eDavid Li	for (list = serv_adapter->records; list; list = list->next) {
2811591693c7b415e9869157c711fe11263c95d74eDavid Li		struct record_data *data = list->data;
2821591693c7b415e9869157c711fe11263c95d74eDavid Li		if (handle == data->handle && !strcmp(sender, data->sender))
2831591693c7b415e9869157c711fe11263c95d74eDavid Li			return data;
2841591693c7b415e9869157c711fe11263c95d74eDavid Li	}
2851591693c7b415e9869157c711fe11263c95d74eDavid Li
2861591693c7b415e9869157c711fe11263c95d74eDavid Li	return NULL;
2871591693c7b415e9869157c711fe11263c95d74eDavid Li}
2881591693c7b415e9869157c711fe11263c95d74eDavid Li
2891591693c7b415e9869157c711fe11263c95d74eDavid Listatic struct pending_auth *next_pending(struct service_adapter *serv_adapter)
2901591693c7b415e9869157c711fe11263c95d74eDavid Li{
2911591693c7b415e9869157c711fe11263c95d74eDavid Li	GSList *l = serv_adapter->pending_list;
2921591693c7b415e9869157c711fe11263c95d74eDavid Li
2931591693c7b415e9869157c711fe11263c95d74eDavid Li	if (l) {
2941591693c7b415e9869157c711fe11263c95d74eDavid Li		struct pending_auth *auth = l->data;
2951591693c7b415e9869157c711fe11263c95d74eDavid Li		return auth;
2961591693c7b415e9869157c711fe11263c95d74eDavid Li	}
2971591693c7b415e9869157c711fe11263c95d74eDavid Li
2981591693c7b415e9869157c711fe11263c95d74eDavid Li	return NULL;
2991591693c7b415e9869157c711fe11263c95d74eDavid Li}
3001591693c7b415e9869157c711fe11263c95d74eDavid Li
3011591693c7b415e9869157c711fe11263c95d74eDavid Listatic struct pending_auth *find_pending_by_sender(
3021591693c7b415e9869157c711fe11263c95d74eDavid Li			struct service_adapter *serv_adapter,
3031591693c7b415e9869157c711fe11263c95d74eDavid Li			const char *sender)
3041591693c7b415e9869157c711fe11263c95d74eDavid Li{
3051591693c7b415e9869157c711fe11263c95d74eDavid Li	GSList *l = serv_adapter->pending_list;
3061591693c7b415e9869157c711fe11263c95d74eDavid Li
3071591693c7b415e9869157c711fe11263c95d74eDavid Li	for (; l; l = l->next) {
3081591693c7b415e9869157c711fe11263c95d74eDavid Li		struct pending_auth *auth = l->data;
3091591693c7b415e9869157c711fe11263c95d74eDavid Li		if (g_str_equal(auth->sender, sender))
3101591693c7b415e9869157c711fe11263c95d74eDavid Li			return auth;
3111591693c7b415e9869157c711fe11263c95d74eDavid Li	}
3121591693c7b415e9869157c711fe11263c95d74eDavid Li
3131591693c7b415e9869157c711fe11263c95d74eDavid Li	return NULL;
3141591693c7b415e9869157c711fe11263c95d74eDavid Li}
3151591693c7b415e9869157c711fe11263c95d74eDavid Li
3161591693c7b415e9869157c711fe11263c95d74eDavid Listatic void exit_callback(DBusConnection *conn, void *user_data)
3171591693c7b415e9869157c711fe11263c95d74eDavid Li{
3181591693c7b415e9869157c711fe11263c95d74eDavid Li	struct record_data *user_record = user_data;
3191591693c7b415e9869157c711fe11263c95d74eDavid Li	struct service_adapter *serv_adapter = user_record->serv_adapter;
3201591693c7b415e9869157c711fe11263c95d74eDavid Li	struct pending_auth *auth;
3211591693c7b415e9869157c711fe11263c95d74eDavid Li
3221591693c7b415e9869157c711fe11263c95d74eDavid Li	DBG("remove record");
3231591693c7b415e9869157c711fe11263c95d74eDavid Li
3241591693c7b415e9869157c711fe11263c95d74eDavid Li	serv_adapter->records = g_slist_remove(serv_adapter->records,
3251591693c7b415e9869157c711fe11263c95d74eDavid Li						user_record);
3261591693c7b415e9869157c711fe11263c95d74eDavid Li
3271591693c7b415e9869157c711fe11263c95d74eDavid Li	auth = find_pending_by_sender(serv_adapter, user_record->sender);
3283b02c91d7b1fcc777dbdafeb044e0df61e1ff0d8David Li	if (auth) {
3291591693c7b415e9869157c711fe11263c95d74eDavid Li		serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
3301591693c7b415e9869157c711fe11263c95d74eDavid Li							auth);
3311591693c7b415e9869157c711fe11263c95d74eDavid Li		g_free(auth);
3321591693c7b415e9869157c711fe11263c95d74eDavid Li	}
3331591693c7b415e9869157c711fe11263c95d74eDavid Li
3341591693c7b415e9869157c711fe11263c95d74eDavid Li	remove_record_from_server(user_record->handle);
3351591693c7b415e9869157c711fe11263c95d74eDavid Li
3361591693c7b415e9869157c711fe11263c95d74eDavid Li	g_free(user_record->sender);
3371591693c7b415e9869157c711fe11263c95d74eDavid Li	g_free(user_record);
3381591693c7b415e9869157c711fe11263c95d74eDavid Li}
3391591693c7b415e9869157c711fe11263c95d74eDavid Li
3401591693c7b415e9869157c711fe11263c95d74eDavid Listatic inline DBusMessage *invalid_arguments(DBusMessage *msg)
3411591693c7b415e9869157c711fe11263c95d74eDavid Li{
3421591693c7b415e9869157c711fe11263c95d74eDavid Li	return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
3431591693c7b415e9869157c711fe11263c95d74eDavid Li					"Invalid arguments in method call");
3441591693c7b415e9869157c711fe11263c95d74eDavid Li}
3451591693c7b415e9869157c711fe11263c95d74eDavid Li
3461591693c7b415e9869157c711fe11263c95d74eDavid Listatic inline DBusMessage *not_available(DBusMessage *msg)
3471591693c7b415e9869157c711fe11263c95d74eDavid Li{
3481591693c7b415e9869157c711fe11263c95d74eDavid Li	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
3491591693c7b415e9869157c711fe11263c95d74eDavid Li							"Not Available");
3501591693c7b415e9869157c711fe11263c95d74eDavid Li}
3511591693c7b415e9869157c711fe11263c95d74eDavid Li
3521591693c7b415e9869157c711fe11263c95d74eDavid Listatic inline DBusMessage *failed(DBusMessage *msg)
3531591693c7b415e9869157c711fe11263c95d74eDavid Li{
3541591693c7b415e9869157c711fe11263c95d74eDavid Li	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Failed");
3551591693c7b415e9869157c711fe11263c95d74eDavid Li}
3561591693c7b415e9869157c711fe11263c95d74eDavid Li
3571591693c7b415e9869157c711fe11263c95d74eDavid Listatic inline DBusMessage *failed_strerror(DBusMessage *msg, int err)
3581591693c7b415e9869157c711fe11263c95d74eDavid Li{
3591591693c7b415e9869157c711fe11263c95d74eDavid Li	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
3601591693c7b415e9869157c711fe11263c95d74eDavid Li							"%s", strerror(err));
3611591693c7b415e9869157c711fe11263c95d74eDavid Li}
3621591693c7b415e9869157c711fe11263c95d74eDavid Li
3631591693c7b415e9869157c711fe11263c95d74eDavid Listatic inline DBusMessage *not_authorized(DBusMessage *msg)
3641591693c7b415e9869157c711fe11263c95d74eDavid Li{
3651591693c7b415e9869157c711fe11263c95d74eDavid Li	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized",
3661591693c7b415e9869157c711fe11263c95d74eDavid Li					"Not Authorized");
3671591693c7b415e9869157c711fe11263c95d74eDavid Li}
3681591693c7b415e9869157c711fe11263c95d74eDavid Li
3691591693c7b415e9869157c711fe11263c95d74eDavid Listatic inline DBusMessage *does_not_exist(DBusMessage *msg)
3701591693c7b415e9869157c711fe11263c95d74eDavid Li{
3711591693c7b415e9869157c711fe11263c95d74eDavid Li	return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist",
3721591693c7b415e9869157c711fe11263c95d74eDavid Li					"Does Not Exist");
3731591693c7b415e9869157c711fe11263c95d74eDavid Li}
3741591693c7b415e9869157c711fe11263c95d74eDavid Li
3751591693c7b415e9869157c711fe11263c95d74eDavid Listatic int add_xml_record(DBusConnection *conn, const char *sender,
3761591693c7b415e9869157c711fe11263c95d74eDavid Li			struct service_adapter *serv_adapter,
3771591693c7b415e9869157c711fe11263c95d74eDavid Li			const char *record, dbus_uint32_t *handle)
3781591693c7b415e9869157c711fe11263c95d74eDavid Li{
3791591693c7b415e9869157c711fe11263c95d74eDavid Li	struct record_data *user_record;
3801591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_record_t *sdp_record;
3811591693c7b415e9869157c711fe11263c95d74eDavid Li	bdaddr_t src;
3821591693c7b415e9869157c711fe11263c95d74eDavid Li
3831591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_record = sdp_xml_parse_record(record, strlen(record));
3841591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!sdp_record) {
3851591693c7b415e9869157c711fe11263c95d74eDavid Li		error("Parsing of XML service record failed");
3861591693c7b415e9869157c711fe11263c95d74eDavid Li		return -EIO;
3871591693c7b415e9869157c711fe11263c95d74eDavid Li	}
3881591693c7b415e9869157c711fe11263c95d74eDavid Li
3891591693c7b415e9869157c711fe11263c95d74eDavid Li	if (serv_adapter->adapter)
3901591693c7b415e9869157c711fe11263c95d74eDavid Li		adapter_get_address(serv_adapter->adapter, &src);
3911591693c7b415e9869157c711fe11263c95d74eDavid Li	else
3921591693c7b415e9869157c711fe11263c95d74eDavid Li		bacpy(&src, BDADDR_ANY);
3931591693c7b415e9869157c711fe11263c95d74eDavid Li
3941591693c7b415e9869157c711fe11263c95d74eDavid Li	if (add_record_to_server(&src, sdp_record) < 0) {
3951591693c7b415e9869157c711fe11263c95d74eDavid Li		error("Failed to register service record");
3961591693c7b415e9869157c711fe11263c95d74eDavid Li		sdp_record_free(sdp_record);
3971591693c7b415e9869157c711fe11263c95d74eDavid Li		return -EIO;
3981591693c7b415e9869157c711fe11263c95d74eDavid Li	}
3991591693c7b415e9869157c711fe11263c95d74eDavid Li
4001591693c7b415e9869157c711fe11263c95d74eDavid Li	user_record = g_new0(struct record_data, 1);
4011591693c7b415e9869157c711fe11263c95d74eDavid Li	user_record->handle = sdp_record->handle;
4021591693c7b415e9869157c711fe11263c95d74eDavid Li	user_record->sender = g_strdup(sender);
4031591693c7b415e9869157c711fe11263c95d74eDavid Li	user_record->serv_adapter = serv_adapter;
4041591693c7b415e9869157c711fe11263c95d74eDavid Li	user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender,
4051591693c7b415e9869157c711fe11263c95d74eDavid Li					exit_callback, user_record, NULL);
4061591693c7b415e9869157c711fe11263c95d74eDavid Li
4071591693c7b415e9869157c711fe11263c95d74eDavid Li	serv_adapter->records = g_slist_append(serv_adapter->records,
4081591693c7b415e9869157c711fe11263c95d74eDavid Li								user_record);
4091591693c7b415e9869157c711fe11263c95d74eDavid Li
4101591693c7b415e9869157c711fe11263c95d74eDavid Li	DBG("listener_id %d", user_record->listener_id);
4111591693c7b415e9869157c711fe11263c95d74eDavid Li
4121591693c7b415e9869157c711fe11263c95d74eDavid Li	*handle = user_record->handle;
4131591693c7b415e9869157c711fe11263c95d74eDavid Li
4141591693c7b415e9869157c711fe11263c95d74eDavid Li	return 0;
4151591693c7b415e9869157c711fe11263c95d74eDavid Li}
4161591693c7b415e9869157c711fe11263c95d74eDavid Li
4171591693c7b415e9869157c711fe11263c95d74eDavid Listatic DBusMessage *update_record(DBusConnection *conn, DBusMessage *msg,
418d50d9a90a0df4d706421850e17c0fbd85bf710eeDavid Li		struct service_adapter *serv_adapter,
4191591693c7b415e9869157c711fe11263c95d74eDavid Li		dbus_uint32_t handle, sdp_record_t *sdp_record)
4201591693c7b415e9869157c711fe11263c95d74eDavid Li{
4211591693c7b415e9869157c711fe11263c95d74eDavid Li	bdaddr_t src;
4221591693c7b415e9869157c711fe11263c95d74eDavid Li	int err;
4231591693c7b415e9869157c711fe11263c95d74eDavid Li
4241591693c7b415e9869157c711fe11263c95d74eDavid Li	if (remove_record_from_server(handle) < 0) {
4251591693c7b415e9869157c711fe11263c95d74eDavid Li		sdp_record_free(sdp_record);
4261591693c7b415e9869157c711fe11263c95d74eDavid Li		return g_dbus_create_error(msg,
4271591693c7b415e9869157c711fe11263c95d74eDavid Li				ERROR_INTERFACE ".NotAvailable",
4281591693c7b415e9869157c711fe11263c95d74eDavid Li				"Not Available");
4291591693c7b415e9869157c711fe11263c95d74eDavid Li	}
4301591693c7b415e9869157c711fe11263c95d74eDavid Li
4311591693c7b415e9869157c711fe11263c95d74eDavid Li	if (serv_adapter->adapter)
4321591693c7b415e9869157c711fe11263c95d74eDavid Li		adapter_get_address(serv_adapter->adapter, &src);
4331591693c7b415e9869157c711fe11263c95d74eDavid Li	else
4341591693c7b415e9869157c711fe11263c95d74eDavid Li		bacpy(&src, BDADDR_ANY);
4351591693c7b415e9869157c711fe11263c95d74eDavid Li
4361591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_record->handle = handle;
4371591693c7b415e9869157c711fe11263c95d74eDavid Li	err = add_record_to_server(&src, sdp_record);
4381591693c7b415e9869157c711fe11263c95d74eDavid Li	if (err < 0) {
4391591693c7b415e9869157c711fe11263c95d74eDavid Li		sdp_record_free(sdp_record);
4401591693c7b415e9869157c711fe11263c95d74eDavid Li		error("Failed to update the service record");
4411591693c7b415e9869157c711fe11263c95d74eDavid Li		return g_dbus_create_error(msg,
4421591693c7b415e9869157c711fe11263c95d74eDavid Li				ERROR_INTERFACE ".Failed",
4431591693c7b415e9869157c711fe11263c95d74eDavid Li				"%s", strerror(EIO));
4441591693c7b415e9869157c711fe11263c95d74eDavid Li	}
4451591693c7b415e9869157c711fe11263c95d74eDavid Li
4461591693c7b415e9869157c711fe11263c95d74eDavid Li	return dbus_message_new_method_return(msg);
4471591693c7b415e9869157c711fe11263c95d74eDavid Li}
4481591693c7b415e9869157c711fe11263c95d74eDavid Li
4491591693c7b415e9869157c711fe11263c95d74eDavid Listatic DBusMessage *update_xml_record(DBusConnection *conn,
4501591693c7b415e9869157c711fe11263c95d74eDavid Li				DBusMessage *msg,
4511591693c7b415e9869157c711fe11263c95d74eDavid Li				struct service_adapter *serv_adapter)
4521591693c7b415e9869157c711fe11263c95d74eDavid Li{
4531591693c7b415e9869157c711fe11263c95d74eDavid Li	struct record_data *user_record;
4543b02c91d7b1fcc777dbdafeb044e0df61e1ff0d8David Li	sdp_record_t *sdp_record;
4551591693c7b415e9869157c711fe11263c95d74eDavid Li	const char *record;
4561591693c7b415e9869157c711fe11263c95d74eDavid Li	dbus_uint32_t handle;
4571591693c7b415e9869157c711fe11263c95d74eDavid Li	int len;
4581591693c7b415e9869157c711fe11263c95d74eDavid Li
4591591693c7b415e9869157c711fe11263c95d74eDavid Li	if (dbus_message_get_args(msg, NULL,
4601591693c7b415e9869157c711fe11263c95d74eDavid Li				DBUS_TYPE_UINT32, &handle,
4611591693c7b415e9869157c711fe11263c95d74eDavid Li				DBUS_TYPE_STRING, &record,
4621591693c7b415e9869157c711fe11263c95d74eDavid Li				DBUS_TYPE_INVALID) == FALSE)
4631591693c7b415e9869157c711fe11263c95d74eDavid Li		return NULL;
4641591693c7b415e9869157c711fe11263c95d74eDavid Li
4651591693c7b415e9869157c711fe11263c95d74eDavid Li	len = (record ? strlen(record) : 0);
4661591693c7b415e9869157c711fe11263c95d74eDavid Li	if (len == 0)
4671591693c7b415e9869157c711fe11263c95d74eDavid Li		return invalid_arguments(msg);
4681591693c7b415e9869157c711fe11263c95d74eDavid Li
4691591693c7b415e9869157c711fe11263c95d74eDavid Li	user_record = find_record(serv_adapter, handle,
4701591693c7b415e9869157c711fe11263c95d74eDavid Li				dbus_message_get_sender(msg));
4711591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!user_record)
4721591693c7b415e9869157c711fe11263c95d74eDavid Li		return g_dbus_create_error(msg,
4731591693c7b415e9869157c711fe11263c95d74eDavid Li				ERROR_INTERFACE ".NotAvailable",
4741591693c7b415e9869157c711fe11263c95d74eDavid Li				"Not Available");
4751591693c7b415e9869157c711fe11263c95d74eDavid Li
4761591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_record = sdp_xml_parse_record(record, len);
4771591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!sdp_record) {
4781591693c7b415e9869157c711fe11263c95d74eDavid Li		error("Parsing of XML service record failed");
4791591693c7b415e9869157c711fe11263c95d74eDavid Li		sdp_record_free(sdp_record);
4801591693c7b415e9869157c711fe11263c95d74eDavid Li		return g_dbus_create_error(msg,
4811591693c7b415e9869157c711fe11263c95d74eDavid Li				ERROR_INTERFACE ".Failed",
4821591693c7b415e9869157c711fe11263c95d74eDavid Li				"%s", strerror(EIO));
4831591693c7b415e9869157c711fe11263c95d74eDavid Li	}
4841591693c7b415e9869157c711fe11263c95d74eDavid Li
4851591693c7b415e9869157c711fe11263c95d74eDavid Li	return update_record(conn, msg, serv_adapter, handle, sdp_record);
4861591693c7b415e9869157c711fe11263c95d74eDavid Li}
4871591693c7b415e9869157c711fe11263c95d74eDavid Li
4881591693c7b415e9869157c711fe11263c95d74eDavid Listatic int remove_record(DBusConnection *conn, const char *sender,
4891591693c7b415e9869157c711fe11263c95d74eDavid Li			struct service_adapter *serv_adapter,
4901591693c7b415e9869157c711fe11263c95d74eDavid Li			dbus_uint32_t handle)
4911591693c7b415e9869157c711fe11263c95d74eDavid Li{
4921591693c7b415e9869157c711fe11263c95d74eDavid Li	struct record_data *user_record;
4931591693c7b415e9869157c711fe11263c95d74eDavid Li
4941591693c7b415e9869157c711fe11263c95d74eDavid Li	DBG("remove record 0x%x", handle);
4951591693c7b415e9869157c711fe11263c95d74eDavid Li
4961591693c7b415e9869157c711fe11263c95d74eDavid Li	user_record = find_record(serv_adapter, handle, sender);
4971591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!user_record)
4981591693c7b415e9869157c711fe11263c95d74eDavid Li		return -1;
4991591693c7b415e9869157c711fe11263c95d74eDavid Li
5001591693c7b415e9869157c711fe11263c95d74eDavid Li	DBG("listner_id %d", user_record->listener_id);
5011591693c7b415e9869157c711fe11263c95d74eDavid Li
5021591693c7b415e9869157c711fe11263c95d74eDavid Li	g_dbus_remove_watch(conn, user_record->listener_id);
5031591693c7b415e9869157c711fe11263c95d74eDavid Li
5041591693c7b415e9869157c711fe11263c95d74eDavid Li	exit_callback(conn, user_record);
5051591693c7b415e9869157c711fe11263c95d74eDavid Li
5061591693c7b415e9869157c711fe11263c95d74eDavid Li	return 0;
5071591693c7b415e9869157c711fe11263c95d74eDavid Li}
5081591693c7b415e9869157c711fe11263c95d74eDavid Li
5091591693c7b415e9869157c711fe11263c95d74eDavid Listatic DBusMessage *add_service_record(DBusConnection *conn,
5101591693c7b415e9869157c711fe11263c95d74eDavid Li					DBusMessage *msg, void *data)
5111591693c7b415e9869157c711fe11263c95d74eDavid Li{
5121591693c7b415e9869157c711fe11263c95d74eDavid Li	struct service_adapter *serv_adapter = data;
5131591693c7b415e9869157c711fe11263c95d74eDavid Li	DBusMessage *reply;
5141591693c7b415e9869157c711fe11263c95d74eDavid Li	const char *sender, *record;
5151591693c7b415e9869157c711fe11263c95d74eDavid Li	dbus_uint32_t handle;
5161591693c7b415e9869157c711fe11263c95d74eDavid Li	int err;
5171591693c7b415e9869157c711fe11263c95d74eDavid Li
5181591693c7b415e9869157c711fe11263c95d74eDavid Li	if (dbus_message_get_args(msg, NULL,
5191591693c7b415e9869157c711fe11263c95d74eDavid Li			DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE)
5201591693c7b415e9869157c711fe11263c95d74eDavid Li		return NULL;
5211591693c7b415e9869157c711fe11263c95d74eDavid Li
5221591693c7b415e9869157c711fe11263c95d74eDavid Li	sender = dbus_message_get_sender(msg);
5231591693c7b415e9869157c711fe11263c95d74eDavid Li	err = add_xml_record(conn, sender, serv_adapter, record, &handle);
5241591693c7b415e9869157c711fe11263c95d74eDavid Li	if (err < 0)
5251591693c7b415e9869157c711fe11263c95d74eDavid Li		return failed_strerror(msg, err);
5261591693c7b415e9869157c711fe11263c95d74eDavid Li
5271591693c7b415e9869157c711fe11263c95d74eDavid Li	reply = dbus_message_new_method_return(msg);
5281591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!reply)
5291591693c7b415e9869157c711fe11263c95d74eDavid Li		return NULL;
5301591693c7b415e9869157c711fe11263c95d74eDavid Li
5311591693c7b415e9869157c711fe11263c95d74eDavid Li	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &handle,
5321591693c7b415e9869157c711fe11263c95d74eDavid Li							DBUS_TYPE_INVALID);
5331591693c7b415e9869157c711fe11263c95d74eDavid Li
5341591693c7b415e9869157c711fe11263c95d74eDavid Li	return reply;
5351591693c7b415e9869157c711fe11263c95d74eDavid Li}
5361591693c7b415e9869157c711fe11263c95d74eDavid Li
5371591693c7b415e9869157c711fe11263c95d74eDavid Listatic DBusMessage *update_service_record(DBusConnection *conn,
5381591693c7b415e9869157c711fe11263c95d74eDavid Li					DBusMessage *msg, void *data)
5391591693c7b415e9869157c711fe11263c95d74eDavid Li{
5401591693c7b415e9869157c711fe11263c95d74eDavid Li	struct service_adapter *serv_adapter = data;
5411591693c7b415e9869157c711fe11263c95d74eDavid Li
5421591693c7b415e9869157c711fe11263c95d74eDavid Li	return update_xml_record(conn, msg, serv_adapter);
5431591693c7b415e9869157c711fe11263c95d74eDavid Li}
5441591693c7b415e9869157c711fe11263c95d74eDavid Li
5451591693c7b415e9869157c711fe11263c95d74eDavid Listatic DBusMessage *remove_service_record(DBusConnection *conn,
5461591693c7b415e9869157c711fe11263c95d74eDavid Li					DBusMessage *msg, void *data)
5471591693c7b415e9869157c711fe11263c95d74eDavid Li{
5481591693c7b415e9869157c711fe11263c95d74eDavid Li	struct service_adapter *serv_adapter = data;
5491591693c7b415e9869157c711fe11263c95d74eDavid Li	dbus_uint32_t handle;
5501591693c7b415e9869157c711fe11263c95d74eDavid Li	const char *sender;
5511591693c7b415e9869157c711fe11263c95d74eDavid Li
5521591693c7b415e9869157c711fe11263c95d74eDavid Li	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
5531591693c7b415e9869157c711fe11263c95d74eDavid Li						DBUS_TYPE_INVALID) == FALSE)
5541591693c7b415e9869157c711fe11263c95d74eDavid Li		return NULL;
5551591693c7b415e9869157c711fe11263c95d74eDavid Li
5561591693c7b415e9869157c711fe11263c95d74eDavid Li	sender = dbus_message_get_sender(msg);
5571591693c7b415e9869157c711fe11263c95d74eDavid Li
5581591693c7b415e9869157c711fe11263c95d74eDavid Li	if (remove_record(conn, sender, serv_adapter, handle) < 0)
5591591693c7b415e9869157c711fe11263c95d74eDavid Li		return not_available(msg);
5601591693c7b415e9869157c711fe11263c95d74eDavid Li
5611591693c7b415e9869157c711fe11263c95d74eDavid Li	return dbus_message_new_method_return(msg);
5621591693c7b415e9869157c711fe11263c95d74eDavid Li}
5631591693c7b415e9869157c711fe11263c95d74eDavid Li
5641591693c7b415e9869157c711fe11263c95d74eDavid Listatic void auth_cb(DBusError *derr, void *user_data)
5651591693c7b415e9869157c711fe11263c95d74eDavid Li{
5661591693c7b415e9869157c711fe11263c95d74eDavid Li	struct service_adapter *serv_adapter = user_data;
5671591693c7b415e9869157c711fe11263c95d74eDavid Li	DBusMessage *reply;
5681591693c7b415e9869157c711fe11263c95d74eDavid Li	struct pending_auth *auth;
5691591693c7b415e9869157c711fe11263c95d74eDavid Li	bdaddr_t src;
5701591693c7b415e9869157c711fe11263c95d74eDavid Li
5711591693c7b415e9869157c711fe11263c95d74eDavid Li	auth = next_pending(serv_adapter);
5721591693c7b415e9869157c711fe11263c95d74eDavid Li	if (auth == NULL) {
5731591693c7b415e9869157c711fe11263c95d74eDavid Li		info("Authorization cancelled: Client exited");
5741591693c7b415e9869157c711fe11263c95d74eDavid Li		return;
5753b02c91d7b1fcc777dbdafeb044e0df61e1ff0d8David Li	}
5761591693c7b415e9869157c711fe11263c95d74eDavid Li
5771591693c7b415e9869157c711fe11263c95d74eDavid Li	if (derr) {
5781591693c7b415e9869157c711fe11263c95d74eDavid Li		error("Access denied: %s", derr->message);
5791591693c7b415e9869157c711fe11263c95d74eDavid Li
5801591693c7b415e9869157c711fe11263c95d74eDavid Li		reply = not_authorized(auth->msg);
5811591693c7b415e9869157c711fe11263c95d74eDavid Li		dbus_message_unref(auth->msg);
5821591693c7b415e9869157c711fe11263c95d74eDavid Li		g_dbus_send_message(auth->conn, reply);
5831591693c7b415e9869157c711fe11263c95d74eDavid Li		goto done;
5841591693c7b415e9869157c711fe11263c95d74eDavid Li	}
5851591693c7b415e9869157c711fe11263c95d74eDavid Li
5861591693c7b415e9869157c711fe11263c95d74eDavid Li	g_dbus_send_reply(auth->conn, auth->msg,
5871591693c7b415e9869157c711fe11263c95d74eDavid Li			DBUS_TYPE_INVALID);
5881591693c7b415e9869157c711fe11263c95d74eDavid Li
5891591693c7b415e9869157c711fe11263c95d74eDavid Lidone:
5901591693c7b415e9869157c711fe11263c95d74eDavid Li	dbus_connection_unref(auth->conn);
5911591693c7b415e9869157c711fe11263c95d74eDavid Li
5921591693c7b415e9869157c711fe11263c95d74eDavid Li	serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
5931591693c7b415e9869157c711fe11263c95d74eDavid Li									auth);
5941591693c7b415e9869157c711fe11263c95d74eDavid Li	g_free(auth);
5951591693c7b415e9869157c711fe11263c95d74eDavid Li
5961591693c7b415e9869157c711fe11263c95d74eDavid Li	auth = next_pending(serv_adapter);
5971591693c7b415e9869157c711fe11263c95d74eDavid Li	if (auth == NULL)
5981591693c7b415e9869157c711fe11263c95d74eDavid Li		return;
5991591693c7b415e9869157c711fe11263c95d74eDavid Li
6001591693c7b415e9869157c711fe11263c95d74eDavid Li	if (serv_adapter->adapter)
6011591693c7b415e9869157c711fe11263c95d74eDavid Li		adapter_get_address(serv_adapter->adapter, &src);
6021591693c7b415e9869157c711fe11263c95d74eDavid Li	else
6031591693c7b415e9869157c711fe11263c95d74eDavid Li		bacpy(&src, BDADDR_ANY);
6041591693c7b415e9869157c711fe11263c95d74eDavid Li
6051591693c7b415e9869157c711fe11263c95d74eDavid Li	btd_request_authorization(&src, &auth->dst,
6061591693c7b415e9869157c711fe11263c95d74eDavid Li					auth->uuid, auth_cb, serv_adapter);
6071591693c7b415e9869157c711fe11263c95d74eDavid Li}
6081591693c7b415e9869157c711fe11263c95d74eDavid Li
6091591693c7b415e9869157c711fe11263c95d74eDavid Listatic DBusMessage *request_authorization(DBusConnection *conn,
6101591693c7b415e9869157c711fe11263c95d74eDavid Li						DBusMessage *msg, void *data)
6111591693c7b415e9869157c711fe11263c95d74eDavid Li{
6121591693c7b415e9869157c711fe11263c95d74eDavid Li	struct record_data *user_record;
6131591693c7b415e9869157c711fe11263c95d74eDavid Li	struct service_adapter *serv_adapter = data;
6141591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_record_t *record;
6151591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_list_t *services;
6161591693c7b415e9869157c711fe11263c95d74eDavid Li	const char *sender;
6171591693c7b415e9869157c711fe11263c95d74eDavid Li	dbus_uint32_t handle;
6181591693c7b415e9869157c711fe11263c95d74eDavid Li	const char *address;
6191591693c7b415e9869157c711fe11263c95d74eDavid Li	struct pending_auth *auth;
6201591693c7b415e9869157c711fe11263c95d74eDavid Li	char uuid_str[MAX_LEN_UUID_STR];
6211591693c7b415e9869157c711fe11263c95d74eDavid Li	uuid_t *uuid, *uuid128;
6221591693c7b415e9869157c711fe11263c95d74eDavid Li	bdaddr_t src;
6231591693c7b415e9869157c711fe11263c95d74eDavid Li
6241591693c7b415e9869157c711fe11263c95d74eDavid Li	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
6251591693c7b415e9869157c711fe11263c95d74eDavid Li					DBUS_TYPE_UINT32, &handle,
6261591693c7b415e9869157c711fe11263c95d74eDavid Li					DBUS_TYPE_INVALID) == FALSE)
6271591693c7b415e9869157c711fe11263c95d74eDavid Li		return NULL;
6281591693c7b415e9869157c711fe11263c95d74eDavid Li
6291591693c7b415e9869157c711fe11263c95d74eDavid Li	sender = dbus_message_get_sender(msg);
6301591693c7b415e9869157c711fe11263c95d74eDavid Li	if (find_pending_by_sender(serv_adapter, sender))
6311591693c7b415e9869157c711fe11263c95d74eDavid Li		return failed(msg);
6321591693c7b415e9869157c711fe11263c95d74eDavid Li
6331591693c7b415e9869157c711fe11263c95d74eDavid Li	user_record = find_record(serv_adapter, handle, sender);
6341591693c7b415e9869157c711fe11263c95d74eDavid Li	if (!user_record) {
6351591693c7b415e9869157c711fe11263c95d74eDavid Li		user_record = find_record(serv_adapter_any, handle, sender);
6361591693c7b415e9869157c711fe11263c95d74eDavid Li		if (!user_record)
6371591693c7b415e9869157c711fe11263c95d74eDavid Li			return not_authorized(msg);
6381591693c7b415e9869157c711fe11263c95d74eDavid Li	}
6391591693c7b415e9869157c711fe11263c95d74eDavid Li
6401591693c7b415e9869157c711fe11263c95d74eDavid Li	record = sdp_record_find(user_record->handle);
6411591693c7b415e9869157c711fe11263c95d74eDavid Li	if (record == NULL)
6421591693c7b415e9869157c711fe11263c95d74eDavid Li		return not_authorized(msg);
6431591693c7b415e9869157c711fe11263c95d74eDavid Li
6441591693c7b415e9869157c711fe11263c95d74eDavid Li	if (sdp_get_service_classes(record, &services) < 0) {
6451591693c7b415e9869157c711fe11263c95d74eDavid Li		sdp_record_free(record);
6461591693c7b415e9869157c711fe11263c95d74eDavid Li		return not_authorized(msg);
6471591693c7b415e9869157c711fe11263c95d74eDavid Li	}
6481591693c7b415e9869157c711fe11263c95d74eDavid Li
6491591693c7b415e9869157c711fe11263c95d74eDavid Li	if (services == NULL)
6501591693c7b415e9869157c711fe11263c95d74eDavid Li		return not_authorized(msg);
6511591693c7b415e9869157c711fe11263c95d74eDavid Li
6521591693c7b415e9869157c711fe11263c95d74eDavid Li	uuid = services->data;
6531591693c7b415e9869157c711fe11263c95d74eDavid Li	uuid128 = sdp_uuid_to_uuid128(uuid);
6541591693c7b415e9869157c711fe11263c95d74eDavid Li
6551591693c7b415e9869157c711fe11263c95d74eDavid Li	sdp_list_free(services, bt_free);
6561591693c7b415e9869157c711fe11263c95d74eDavid Li
6571591693c7b415e9869157c711fe11263c95d74eDavid Li	if (sdp_uuid2strn(uuid128, uuid_str, MAX_LEN_UUID_STR) < 0) {
6581591693c7b415e9869157c711fe11263c95d74eDavid Li		bt_free(uuid128);
6591591693c7b415e9869157c711fe11263c95d74eDavid Li		return not_authorized(msg);
6601591693c7b415e9869157c711fe11263c95d74eDavid Li	}
6611591693c7b415e9869157c711fe11263c95d74eDavid Li	bt_free(uuid128);
6621591693c7b415e9869157c711fe11263c95d74eDavid Li
6631591693c7b415e9869157c711fe11263c95d74eDavid Li	auth = g_new0(struct pending_auth, 1);
6641591693c7b415e9869157c711fe11263c95d74eDavid Li	auth->msg = dbus_message_ref(msg);
6651591693c7b415e9869157c711fe11263c95d74eDavid Li	auth->conn = dbus_connection_ref(connection);
6661591693c7b415e9869157c711fe11263c95d74eDavid Li	auth->sender = user_record->sender;
6671591693c7b415e9869157c711fe11263c95d74eDavid Li	memcpy(auth->uuid, uuid_str, MAX_LEN_UUID_STR);
6681591693c7b415e9869157c711fe11263c95d74eDavid Li	str2ba(address, &auth->dst);
6691591693c7b415e9869157c711fe11263c95d74eDavid Li
6701591693c7b415e9869157c711fe11263c95d74eDavid Li	serv_adapter->pending_list = g_slist_append(serv_adapter->pending_list,
6711591693c7b415e9869157c711fe11263c95d74eDavid Li									auth);
6721591693c7b415e9869157c711fe11263c95d74eDavid Li
6731591693c7b415e9869157c711fe11263c95d74eDavid Li	auth = next_pending(serv_adapter);
6741591693c7b415e9869157c711fe11263c95d74eDavid Li	if (auth == NULL)
6751591693c7b415e9869157c711fe11263c95d74eDavid Li		return does_not_exist(msg);
6761591693c7b415e9869157c711fe11263c95d74eDavid Li
6771591693c7b415e9869157c711fe11263c95d74eDavid Li	if (serv_adapter->adapter)
6781591693c7b415e9869157c711fe11263c95d74eDavid Li		adapter_get_address(serv_adapter->adapter, &src);
6791591693c7b415e9869157c711fe11263c95d74eDavid Li	else
6801591693c7b415e9869157c711fe11263c95d74eDavid Li		bacpy(&src, BDADDR_ANY);
6811591693c7b415e9869157c711fe11263c95d74eDavid Li
6821591693c7b415e9869157c711fe11263c95d74eDavid Li	if (btd_request_authorization(&src, &auth->dst, auth->uuid, auth_cb,
6831591693c7b415e9869157c711fe11263c95d74eDavid Li							serv_adapter) < 0) {
6841591693c7b415e9869157c711fe11263c95d74eDavid Li		serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
6851591693c7b415e9869157c711fe11263c95d74eDavid Li									auth);
6861591693c7b415e9869157c711fe11263c95d74eDavid Li		g_free(auth);
6871591693c7b415e9869157c711fe11263c95d74eDavid Li		return not_authorized(msg);
6881591693c7b415e9869157c711fe11263c95d74eDavid Li	}
6891591693c7b415e9869157c711fe11263c95d74eDavid Li
6901591693c7b415e9869157c711fe11263c95d74eDavid Li	return NULL;
6911591693c7b415e9869157c711fe11263c95d74eDavid Li}
6921591693c7b415e9869157c711fe11263c95d74eDavid Li
6931591693c7b415e9869157c711fe11263c95d74eDavid Listatic DBusMessage *cancel_authorization(DBusConnection *conn,
6941591693c7b415e9869157c711fe11263c95d74eDavid Li						DBusMessage *msg, void *data)
6951591693c7b415e9869157c711fe11263c95d74eDavid Li{
6961591693c7b415e9869157c711fe11263c95d74eDavid Li	DBusMessage *reply;
6971591693c7b415e9869157c711fe11263c95d74eDavid Li	struct service_adapter *serv_adapter = data;
6981591693c7b415e9869157c711fe11263c95d74eDavid Li	struct pending_auth *auth;
6991591693c7b415e9869157c711fe11263c95d74eDavid Li	const gchar *sender;
7001591693c7b415e9869157c711fe11263c95d74eDavid Li	bdaddr_t src;
7011591693c7b415e9869157c711fe11263c95d74eDavid Li
7021591693c7b415e9869157c711fe11263c95d74eDavid Li	sender = dbus_message_get_sender(msg);
7031591693c7b415e9869157c711fe11263c95d74eDavid Li
7041591693c7b415e9869157c711fe11263c95d74eDavid Li	auth = find_pending_by_sender(serv_adapter, sender);
7051591693c7b415e9869157c711fe11263c95d74eDavid Li	if (auth == NULL)
7061591693c7b415e9869157c711fe11263c95d74eDavid Li		return does_not_exist(msg);
7071591693c7b415e9869157c711fe11263c95d74eDavid Li
7081591693c7b415e9869157c711fe11263c95d74eDavid Li	if (serv_adapter->adapter)
7091591693c7b415e9869157c711fe11263c95d74eDavid Li		adapter_get_address(serv_adapter->adapter, &src);
7101591693c7b415e9869157c711fe11263c95d74eDavid Li	else
7111591693c7b415e9869157c711fe11263c95d74eDavid Li		bacpy(&src, BDADDR_ANY);
7121591693c7b415e9869157c711fe11263c95d74eDavid Li
7131591693c7b415e9869157c711fe11263c95d74eDavid Li	btd_cancel_authorization(&src, &auth->dst);
7141591693c7b415e9869157c711fe11263c95d74eDavid Li
7151591693c7b415e9869157c711fe11263c95d74eDavid Li	reply = not_authorized(auth->msg);
7161591693c7b415e9869157c711fe11263c95d74eDavid Li	dbus_message_unref(auth->msg);
7171591693c7b415e9869157c711fe11263c95d74eDavid Li	g_dbus_send_message(auth->conn, reply);
7181591693c7b415e9869157c711fe11263c95d74eDavid Li
7191591693c7b415e9869157c711fe11263c95d74eDavid Li	dbus_connection_unref(auth->conn);
7201591693c7b415e9869157c711fe11263c95d74eDavid Li
7211591693c7b415e9869157c711fe11263c95d74eDavid Li	serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
7221591693c7b415e9869157c711fe11263c95d74eDavid Li									auth);
7231591693c7b415e9869157c711fe11263c95d74eDavid Li	g_free(auth);
7241591693c7b415e9869157c711fe11263c95d74eDavid Li
7251591693c7b415e9869157c711fe11263c95d74eDavid Li	auth = next_pending(serv_adapter);
7261591693c7b415e9869157c711fe11263c95d74eDavid Li	if (auth == NULL)
7271591693c7b415e9869157c711fe11263c95d74eDavid Li		goto done;
7281591693c7b415e9869157c711fe11263c95d74eDavid Li
7291591693c7b415e9869157c711fe11263c95d74eDavid Li	if (serv_adapter->adapter)
7301591693c7b415e9869157c711fe11263c95d74eDavid Li		adapter_get_address(serv_adapter->adapter, &src);
7311591693c7b415e9869157c711fe11263c95d74eDavid Li	else
7321591693c7b415e9869157c711fe11263c95d74eDavid Li		bacpy(&src, BDADDR_ANY);
7331591693c7b415e9869157c711fe11263c95d74eDavid Li
7341591693c7b415e9869157c711fe11263c95d74eDavid Li	btd_request_authorization(&src, &auth->dst,
7351591693c7b415e9869157c711fe11263c95d74eDavid Li					auth->uuid, auth_cb, serv_adapter);
7361591693c7b415e9869157c711fe11263c95d74eDavid Li
7371591693c7b415e9869157c711fe11263c95d74eDavid Lidone:
7381591693c7b415e9869157c711fe11263c95d74eDavid Li	return dbus_message_new_method_return(msg);
7391591693c7b415e9869157c711fe11263c95d74eDavid Li}
7401591693c7b415e9869157c711fe11263c95d74eDavid Li
7411591693c7b415e9869157c711fe11263c95d74eDavid Listatic GDBusMethodTable service_methods[] = {
7421591693c7b415e9869157c711fe11263c95d74eDavid Li	{ "AddRecord",		"s",	"u",	add_service_record	},
7431591693c7b415e9869157c711fe11263c95d74eDavid Li	{ "UpdateRecord",	"us",	"",	update_service_record	},
7441591693c7b415e9869157c711fe11263c95d74eDavid Li	{ "RemoveRecord",	"u",	"",	remove_service_record	},
7451591693c7b415e9869157c711fe11263c95d74eDavid Li	{ "RequestAuthorization","su",	"",	request_authorization,
7461591693c7b415e9869157c711fe11263c95d74eDavid Li						G_DBUS_METHOD_FLAG_ASYNC},
7471591693c7b415e9869157c711fe11263c95d74eDavid Li	{ "CancelAuthorization", "",	"",	cancel_authorization	},
7481591693c7b415e9869157c711fe11263c95d74eDavid Li	{ }
7491591693c7b415e9869157c711fe11263c95d74eDavid Li};
7501591693c7b415e9869157c711fe11263c95d74eDavid Li
7511591693c7b415e9869157c711fe11263c95d74eDavid Listatic void path_unregister(void *data)
7521591693c7b415e9869157c711fe11263c95d74eDavid Li{
7531591693c7b415e9869157c711fe11263c95d74eDavid Li	struct service_adapter *serv_adapter = data;
7541591693c7b415e9869157c711fe11263c95d74eDavid Li	GSList *l, *next = NULL;
7551591693c7b415e9869157c711fe11263c95d74eDavid Li
7561591693c7b415e9869157c711fe11263c95d74eDavid Li	for (l = serv_adapter->records; l != NULL; l = next) {
7571591693c7b415e9869157c711fe11263c95d74eDavid Li		struct record_data *user_record = l->data;
7581591693c7b415e9869157c711fe11263c95d74eDavid Li
7591591693c7b415e9869157c711fe11263c95d74eDavid Li		next = l->next;
7601591693c7b415e9869157c711fe11263c95d74eDavid Li
7611591693c7b415e9869157c711fe11263c95d74eDavid Li		g_dbus_remove_watch(connection, user_record->listener_id);
7621591693c7b415e9869157c711fe11263c95d74eDavid Li		exit_callback(connection, user_record);
7631591693c7b415e9869157c711fe11263c95d74eDavid Li	}
7641591693c7b415e9869157c711fe11263c95d74eDavid Li
7651591693c7b415e9869157c711fe11263c95d74eDavid Li	g_free(serv_adapter);
7661591693c7b415e9869157c711fe11263c95d74eDavid Li}
7671591693c7b415e9869157c711fe11263c95d74eDavid Li
7681591693c7b415e9869157c711fe11263c95d74eDavid Listatic int register_interface(const char *path, struct btd_adapter *adapter)
7691591693c7b415e9869157c711fe11263c95d74eDavid Li{
7701591693c7b415e9869157c711fe11263c95d74eDavid Li	struct service_adapter *serv_adapter;
7711591693c7b415e9869157c711fe11263c95d74eDavid Li
7721591693c7b415e9869157c711fe11263c95d74eDavid Li	DBG("path %s", path);
7731591693c7b415e9869157c711fe11263c95d74eDavid Li
7741591693c7b415e9869157c711fe11263c95d74eDavid Li	serv_adapter = g_try_new0(struct service_adapter, 1);
7751591693c7b415e9869157c711fe11263c95d74eDavid Li	if (serv_adapter == NULL)
7761591693c7b415e9869157c711fe11263c95d74eDavid Li		return -ENOMEM;
7771591693c7b415e9869157c711fe11263c95d74eDavid Li
7781591693c7b415e9869157c711fe11263c95d74eDavid Li	serv_adapter->adapter = adapter;
7791591693c7b415e9869157c711fe11263c95d74eDavid Li	serv_adapter->pending_list = NULL;
7801591693c7b415e9869157c711fe11263c95d74eDavid Li
7811591693c7b415e9869157c711fe11263c95d74eDavid Li	if (g_dbus_register_interface(connection, path, SERVICE_INTERFACE,
7821591693c7b415e9869157c711fe11263c95d74eDavid Li				service_methods, NULL, NULL, serv_adapter,
7831591693c7b415e9869157c711fe11263c95d74eDavid Li						path_unregister) == FALSE) {
7841591693c7b415e9869157c711fe11263c95d74eDavid Li		error("D-Bus failed to register %s interface",
7851591693c7b415e9869157c711fe11263c95d74eDavid Li							SERVICE_INTERFACE);
7861591693c7b415e9869157c711fe11263c95d74eDavid Li		g_free(serv_adapter);
7871591693c7b415e9869157c711fe11263c95d74eDavid Li		return -EIO;
7881591693c7b415e9869157c711fe11263c95d74eDavid Li	}
7891591693c7b415e9869157c711fe11263c95d74eDavid Li
7901591693c7b415e9869157c711fe11263c95d74eDavid Li	DBG("Registered interface %s on path %s", SERVICE_INTERFACE, path);
7911591693c7b415e9869157c711fe11263c95d74eDavid Li
7921591693c7b415e9869157c711fe11263c95d74eDavid Li	if (serv_adapter->adapter == NULL)
7931591693c7b415e9869157c711fe11263c95d74eDavid Li		serv_adapter_any = serv_adapter;
7941591693c7b415e9869157c711fe11263c95d74eDavid Li
7951591693c7b415e9869157c711fe11263c95d74eDavid Li	return 0;
7961591693c7b415e9869157c711fe11263c95d74eDavid Li}
7971591693c7b415e9869157c711fe11263c95d74eDavid Li
7981591693c7b415e9869157c711fe11263c95d74eDavid Listatic void unregister_interface(const char *path)
7991591693c7b415e9869157c711fe11263c95d74eDavid Li{
8001591693c7b415e9869157c711fe11263c95d74eDavid Li	DBG("path %s", path);
8011591693c7b415e9869157c711fe11263c95d74eDavid Li
8021591693c7b415e9869157c711fe11263c95d74eDavid Li	g_dbus_unregister_interface(connection, path, SERVICE_INTERFACE);
8031591693c7b415e9869157c711fe11263c95d74eDavid Li}
8041591693c7b415e9869157c711fe11263c95d74eDavid Li
8051591693c7b415e9869157c711fe11263c95d74eDavid Listatic int service_probe(struct btd_adapter *adapter)
8061591693c7b415e9869157c711fe11263c95d74eDavid Li{
8071591693c7b415e9869157c711fe11263c95d74eDavid Li	register_interface(adapter_get_path(adapter), adapter);
8081591693c7b415e9869157c711fe11263c95d74eDavid Li
8091591693c7b415e9869157c711fe11263c95d74eDavid Li	return 0;
8101591693c7b415e9869157c711fe11263c95d74eDavid Li}
8111591693c7b415e9869157c711fe11263c95d74eDavid Li
8121591693c7b415e9869157c711fe11263c95d74eDavid Listatic void service_remove(struct btd_adapter *adapter)
8131591693c7b415e9869157c711fe11263c95d74eDavid Li{
8141591693c7b415e9869157c711fe11263c95d74eDavid Li	unregister_interface(adapter_get_path(adapter));
8151591693c7b415e9869157c711fe11263c95d74eDavid Li}
8161591693c7b415e9869157c711fe11263c95d74eDavid Li
8171591693c7b415e9869157c711fe11263c95d74eDavid Listatic struct btd_adapter_driver service_driver = {
8181591693c7b415e9869157c711fe11263c95d74eDavid Li	.name	= "service",
8191591693c7b415e9869157c711fe11263c95d74eDavid Li	.probe	= service_probe,
8201591693c7b415e9869157c711fe11263c95d74eDavid Li	.remove	= service_remove,
8211591693c7b415e9869157c711fe11263c95d74eDavid Li};
8221591693c7b415e9869157c711fe11263c95d74eDavid Li
8231591693c7b415e9869157c711fe11263c95d74eDavid Listatic const char *any_path;
8241591693c7b415e9869157c711fe11263c95d74eDavid Li
8251591693c7b415e9869157c711fe11263c95d74eDavid Listatic int service_init(void)
8261591693c7b415e9869157c711fe11263c95d74eDavid Li{
8271591693c7b415e9869157c711fe11263c95d74eDavid Li	int err;
8281591693c7b415e9869157c711fe11263c95d74eDavid Li
8291591693c7b415e9869157c711fe11263c95d74eDavid Li	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
8301591693c7b415e9869157c711fe11263c95d74eDavid Li	if (connection == NULL)
8311591693c7b415e9869157c711fe11263c95d74eDavid Li		return -EIO;
8321591693c7b415e9869157c711fe11263c95d74eDavid Li
8331591693c7b415e9869157c711fe11263c95d74eDavid Li	any_path = btd_adapter_any_request_path();
8341591693c7b415e9869157c711fe11263c95d74eDavid Li	if (any_path != NULL) {
8351591693c7b415e9869157c711fe11263c95d74eDavid Li		if (register_interface(any_path, NULL) < 0) {
8361591693c7b415e9869157c711fe11263c95d74eDavid Li			btd_adapter_any_release_path();
8371591693c7b415e9869157c711fe11263c95d74eDavid Li			any_path = NULL;
838d274f94df69a016386195efcf0640802c7d7d2dcDavid Li		}
839d274f94df69a016386195efcf0640802c7d7d2dcDavid Li	}
8401591693c7b415e9869157c711fe11263c95d74eDavid Li
8411591693c7b415e9869157c711fe11263c95d74eDavid Li	err = btd_register_adapter_driver(&service_driver);
8421591693c7b415e9869157c711fe11263c95d74eDavid Li	if (err < 0) {
8431591693c7b415e9869157c711fe11263c95d74eDavid Li		dbus_connection_unref(connection);
8441591693c7b415e9869157c711fe11263c95d74eDavid Li		return err;
8451591693c7b415e9869157c711fe11263c95d74eDavid Li	}
8461591693c7b415e9869157c711fe11263c95d74eDavid Li
8471591693c7b415e9869157c711fe11263c95d74eDavid Li	return 0;
8481591693c7b415e9869157c711fe11263c95d74eDavid Li}
8491591693c7b415e9869157c711fe11263c95d74eDavid Li
8501591693c7b415e9869157c711fe11263c95d74eDavid Listatic void service_exit(void)
8511591693c7b415e9869157c711fe11263c95d74eDavid Li{
8521591693c7b415e9869157c711fe11263c95d74eDavid Li	btd_unregister_adapter_driver(&service_driver);
8531591693c7b415e9869157c711fe11263c95d74eDavid Li
8541591693c7b415e9869157c711fe11263c95d74eDavid Li	if (any_path != NULL) {
8551591693c7b415e9869157c711fe11263c95d74eDavid Li		unregister_interface(any_path);
8561591693c7b415e9869157c711fe11263c95d74eDavid Li
8571591693c7b415e9869157c711fe11263c95d74eDavid Li		btd_adapter_any_release_path();
8581591693c7b415e9869157c711fe11263c95d74eDavid Li		any_path = NULL;
8591591693c7b415e9869157c711fe11263c95d74eDavid Li	}
8601591693c7b415e9869157c711fe11263c95d74eDavid Li
8611591693c7b415e9869157c711fe11263c95d74eDavid Li	dbus_connection_unref(connection);
8621591693c7b415e9869157c711fe11263c95d74eDavid Li}
8631591693c7b415e9869157c711fe11263c95d74eDavid Li
8641591693c7b415e9869157c711fe11263c95d74eDavid LiBLUETOOTH_PLUGIN_DEFINE(service, VERSION,
8651591693c7b415e9869157c711fe11263c95d74eDavid Li		BLUETOOTH_PLUGIN_PRIORITY_HIGH, service_init, service_exit)
8661591693c7b415e9869157c711fe11263c95d74eDavid Li