1/*
2 *
3 *  BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
6 *  Authors:
7 *  Santiago Carot Nemesio <sancane at gmail.com>
8 *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License as published by
12 *  the Free Software Foundation; either version 2 of the License, or
13 *  (at your option) any later version.
14 *
15 *  This program is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU General Public License for more details.
19 *
20 *  You should have received a copy of the GNU General Public License
21 *  along with this program; if not, write to the Free Software
22 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23 *
24 */
25
26#include <gdbus.h>
27
28#include "log.h"
29#include "error.h"
30#include <stdlib.h>
31#include <stdint.h>
32#include <hdp_types.h>
33#include <hdp_util.h>
34#include <adapter.h>
35#include <device.h>
36#include <hdp.h>
37#include <mcap.h>
38#include <btio.h>
39#include <mcap_lib.h>
40#include <bluetooth/l2cap.h>
41#include <sdpd.h>
42#include "../src/dbus-common.h"
43#include <unistd.h>
44
45#ifndef DBUS_TYPE_UNIX_FD
46	#define DBUS_TYPE_UNIX_FD -1
47#endif
48
49#define ECHO_TIMEOUT	1 /* second */
50#define HDP_ECHO_LEN	15
51
52static DBusConnection *connection = NULL;
53
54static GSList *applications = NULL;
55static GSList *devices = NULL;
56static uint8_t next_app_id = HDP_MDEP_INITIAL;
57
58static GSList *adapters;
59
60static gboolean update_adapter(struct hdp_adapter *adapter);
61static struct hdp_device *create_health_device(DBusConnection *conn,
62						struct btd_device *device);
63static void free_echo_data(struct hdp_echo_data *edata);
64
65struct hdp_create_dc {
66	DBusConnection			*conn;
67	DBusMessage			*msg;
68	struct hdp_application		*app;
69	struct hdp_device		*dev;
70	uint8_t				config;
71	uint8_t				mdep;
72	guint				ref;
73	mcap_mdl_operation_cb		cb;
74};
75
76struct hdp_tmp_dc_data {
77	DBusConnection			*conn;
78	DBusMessage			*msg;
79	struct hdp_channel		*hdp_chann;
80	guint				ref;
81	mcap_mdl_operation_cb		cb;
82};
83
84struct hdp_echo_data {
85	gboolean		echo_done;	/* Is a echo was already done */
86	gpointer		buf;		/* echo packet sent */
87	uint			tid;		/* echo timeout */
88};
89
90static struct hdp_channel *hdp_channel_ref(struct hdp_channel *chan)
91{
92	if (!chan)
93		return NULL;
94
95	chan->ref++;
96
97	DBG("health_channel_ref(%p): ref=%d", chan, chan->ref);
98	return chan;
99}
100
101static void free_health_channel(struct hdp_channel *chan)
102{
103	if (chan->mdep == HDP_MDEP_ECHO) {
104		free_echo_data(chan->edata);
105		chan->edata = NULL;
106	}
107
108	mcap_mdl_unref(chan->mdl);
109	hdp_application_unref(chan->app);
110	health_device_unref(chan->dev);
111	g_free(chan->path);
112	g_free(chan);
113}
114
115static void hdp_channel_unref(struct hdp_channel *chan)
116{
117	if (!chan)
118		return;
119
120	chan->ref --;
121	DBG("health_channel_unref(%p): ref=%d", chan, chan->ref);
122
123	if (chan->ref > 0)
124		return;
125
126	free_health_channel(chan);
127}
128
129static void free_hdp_create_dc(struct hdp_create_dc *dc_data)
130{
131	dbus_message_unref(dc_data->msg);
132	dbus_connection_unref(dc_data->conn);
133	hdp_application_unref(dc_data->app);
134	health_device_unref(dc_data->dev);
135
136	g_free(dc_data);
137}
138
139static struct hdp_create_dc *hdp_create_data_ref(struct hdp_create_dc *dc_data)
140{
141	dc_data->ref++;
142
143	DBG("hdp_create_data_ref(%p): ref=%d", dc_data, dc_data->ref);
144
145	return dc_data;
146}
147
148static void hdp_create_data_unref(struct hdp_create_dc *dc_data)
149{
150	dc_data->ref--;
151
152	DBG("hdp_create_data_unref(%p): ref=%d", dc_data, dc_data->ref);
153
154	if (dc_data->ref > 0)
155		return;
156
157	free_hdp_create_dc(dc_data);
158}
159
160static void free_hdp_conn_dc(struct hdp_tmp_dc_data *data)
161{
162	dbus_message_unref(data->msg);
163	dbus_connection_unref(data->conn);
164	hdp_channel_unref(data->hdp_chann);
165
166	g_free(data);
167}
168
169static struct hdp_tmp_dc_data *hdp_tmp_dc_data_ref(struct hdp_tmp_dc_data *data)
170{
171	data->ref++;
172
173	DBG("hdp_conn_data_ref(%p): ref=%d", data, data->ref);
174
175	return data;
176}
177
178static void hdp_tmp_dc_data_unref(struct hdp_tmp_dc_data *data)
179{
180	data->ref--;
181
182	DBG("hdp_conn_data_unref(%p): ref=%d", data, data->ref);
183
184	if (data->ref > 0)
185		return;
186
187	free_hdp_conn_dc(data);
188}
189
190static int cmp_app_id(gconstpointer a, gconstpointer b)
191{
192	const struct hdp_application *app = a;
193	const uint8_t *id = b;
194
195	return app->id - *id;
196}
197
198static int cmp_adapter(gconstpointer a, gconstpointer b)
199{
200	const struct hdp_adapter *hdp_adapter = a;
201	const struct btd_adapter *adapter = b;
202
203	if (hdp_adapter->btd_adapter == adapter)
204		return 0;
205
206	return -1;
207}
208
209static int cmp_device(gconstpointer a, gconstpointer b)
210{
211	const struct hdp_device *hdp_device = a;
212	const struct btd_device *device = b;
213
214	if (hdp_device->dev == device)
215		return 0;
216
217	return -1;
218}
219
220static gint cmp_dev_addr(gconstpointer a, gconstpointer dst)
221{
222	const struct hdp_device *device = a;
223	bdaddr_t addr;
224
225	device_get_address(device->dev, &addr);
226	return bacmp(&addr, dst);
227}
228
229static gint cmp_dev_mcl(gconstpointer a, gconstpointer mcl)
230{
231	const struct hdp_device *device = a;
232
233	if (mcl == device->mcl)
234		return 0;
235	return -1;
236}
237
238static gint cmp_chan_mdlid(gconstpointer a, gconstpointer b)
239{
240	const struct hdp_channel *chan = a;
241	const uint16_t *mdlid = b;
242
243	return chan->mdlid - *mdlid;
244}
245
246static gint cmp_chan_path(gconstpointer a, gconstpointer b)
247{
248	const struct hdp_channel *chan = a;
249	const char *path = b;
250
251	return g_ascii_strcasecmp(chan->path, path);
252}
253
254static gint cmp_chan_mdl(gconstpointer a, gconstpointer mdl)
255{
256	const struct hdp_channel *chan = a;
257
258	if (chan->mdl == mdl)
259		return 0;
260	return -1;
261}
262
263static uint8_t get_app_id(void)
264{
265	uint8_t id = next_app_id;
266
267	do {
268		GSList *l = g_slist_find_custom(applications, &id, cmp_app_id);
269
270		if (!l) {
271			next_app_id = (id % HDP_MDEP_FINAL) + 1;
272			return id;
273		} else
274			id = (id % HDP_MDEP_FINAL) + 1;
275	} while (id != next_app_id);
276
277	/* No more ids available */
278	return 0;
279}
280
281static int cmp_app(gconstpointer a, gconstpointer b)
282{
283	const struct hdp_application *app = a;
284
285	return g_strcmp0(app->path, b);
286}
287
288static gboolean set_app_path(struct hdp_application *app)
289{
290	app->id = get_app_id();
291	if (!app->id)
292		return FALSE;
293	app->path = g_strdup_printf(MANAGER_PATH "/health_app_%d", app->id);
294
295	return TRUE;
296};
297
298static void device_unref_mcl(struct hdp_device *hdp_device)
299{
300	if (!hdp_device->mcl)
301		return;
302
303	mcap_close_mcl(hdp_device->mcl, FALSE);
304	mcap_mcl_unref(hdp_device->mcl);
305	hdp_device->mcl = NULL;
306	hdp_device->mcl_conn = FALSE;
307}
308
309static void free_health_device(struct hdp_device *device)
310{
311	if (device->conn) {
312		dbus_connection_unref(device->conn);
313		device->conn = NULL;
314	}
315
316	if (device->dev) {
317		btd_device_unref(device->dev);
318		device->dev = NULL;
319	}
320
321	device_unref_mcl(device);
322
323	g_free(device);
324}
325
326static void remove_application(struct hdp_application *app)
327{
328	DBG("Application %s deleted", app->path);
329	hdp_application_unref(app);
330
331	g_slist_foreach(adapters, (GFunc) update_adapter, NULL);
332}
333
334static void client_disconnected(DBusConnection *conn, void *user_data)
335{
336	struct hdp_application *app = user_data;
337
338	DBG("Client disconnected from the bus, deleting hdp application");
339	applications = g_slist_remove(applications, app);
340
341	app->dbus_watcher = 0; /* Watcher shouldn't be freed in this case */
342	remove_application(app);
343}
344
345static DBusMessage *manager_create_application(DBusConnection *conn,
346					DBusMessage *msg, void *user_data)
347{
348	struct hdp_application *app;
349	const char *name;
350	DBusMessageIter iter;
351	GError *err = NULL;
352
353	dbus_message_iter_init(msg, &iter);
354	app = hdp_get_app_config(&iter, &err);
355	if (err) {
356		g_error_free(err);
357		return btd_error_invalid_args(msg);
358	}
359
360	name = dbus_message_get_sender(msg);
361	if (!name) {
362		hdp_application_unref(app);
363		return g_dbus_create_error(msg,
364					ERROR_INTERFACE ".HealthError",
365					"Can't get sender name");
366	}
367
368	if (!set_app_path(app)) {
369		hdp_application_unref(app);
370		return g_dbus_create_error(msg,
371				ERROR_INTERFACE ".HealthError",
372				"Can't get a valid id for the application");
373	}
374
375	app->oname = g_strdup(name);
376	app->conn = dbus_connection_ref(conn);
377
378	applications = g_slist_prepend(applications, app);
379
380	app->dbus_watcher = g_dbus_add_disconnect_watch(conn, name,
381						client_disconnected, app, NULL);
382	g_slist_foreach(adapters, (GFunc) update_adapter, NULL);
383
384	DBG("Health application created with id %s", app->path);
385
386	return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &app->path,
387							DBUS_TYPE_INVALID);
388}
389
390static DBusMessage *manager_destroy_application(DBusConnection *conn,
391					DBusMessage *msg, void *user_data)
392{
393	const char *path;
394	struct hdp_application *app;
395	GSList *l;
396
397	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
398						DBUS_TYPE_INVALID))
399		return btd_error_invalid_args(msg);
400
401	l = g_slist_find_custom(applications, path, cmp_app);
402
403	if (!l)
404		return g_dbus_create_error(msg,
405					ERROR_INTERFACE ".InvalidArguments",
406					"Invalid arguments in method call, "
407					"no such application");
408
409	app = l->data;
410	applications = g_slist_remove(applications, app);
411
412	remove_application(app);
413
414	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
415}
416
417static void manager_path_unregister(gpointer data)
418{
419	g_slist_foreach(applications, (GFunc) hdp_application_unref, NULL);
420
421	g_slist_free(applications);
422	applications = NULL;
423
424	g_slist_foreach(adapters, (GFunc) update_adapter, NULL);
425}
426
427static GDBusMethodTable health_manager_methods[] = {
428	{"CreateApplication", "a{sv}", "o", manager_create_application},
429	{"DestroyApplication", "o", "", manager_destroy_application},
430	{ NULL }
431};
432
433static DBusMessage *channel_get_properties(DBusConnection *conn,
434					DBusMessage *msg, void *user_data)
435{
436	struct hdp_channel *chan = user_data;
437	DBusMessageIter iter, dict;
438	DBusMessage *reply;
439	const char *path;
440	char *type;
441
442	reply = dbus_message_new_method_return(msg);
443	if (!reply)
444		return NULL;
445
446	dbus_message_iter_init_append(reply, &iter);
447
448	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
449			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
450			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
451			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
452
453	path = device_get_path(chan->dev->dev);
454	dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH, &path);
455
456	path = chan->app->path;
457	dict_append_entry(&dict, "Application", DBUS_TYPE_OBJECT_PATH, &path);
458
459	if (chan->config == HDP_RELIABLE_DC)
460		type = g_strdup("Reliable");
461	else
462		type = g_strdup("Streaming");
463
464	dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &type);
465
466	g_free(type);
467
468	dbus_message_iter_close_container(&iter, &dict);
469
470	return reply;
471}
472
473static void hdp_tmp_dc_data_destroy(gpointer data)
474{
475	struct hdp_tmp_dc_data *hdp_conn = data;
476
477	hdp_tmp_dc_data_unref(hdp_conn);
478}
479
480static void abort_mdl_cb(GError *err, gpointer data)
481{
482	struct hdp_device *dev;
483	struct hdp_channel *hdp_chan = data;
484	if (err)
485		error("Aborting error: %s", err->message);
486
487	if (hdp_chan) {
488		dev = hdp_chan->dev;
489		if (dev && hdp_chan->mdep != HDP_MDEP_ECHO)
490			g_dbus_emit_signal(dev->conn,
491						device_get_path(dev->dev),
492						HEALTH_DEVICE,
493						"ChannelConnected",
494						DBUS_TYPE_OBJECT_PATH,
495						&hdp_chan->path,
496						DBUS_TYPE_INVALID);
497	}
498}
499
500static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
501{
502	struct hdp_tmp_dc_data *dc_data = data;
503	DBusMessage *reply;
504	int fd;
505
506	if (err) {
507		struct hdp_channel *chan = dc_data->hdp_chann;
508		GError *gerr = NULL;
509
510		error("%s", err->message);
511		reply = g_dbus_create_error(dc_data->msg,
512					ERROR_INTERFACE ".HealthError",
513					"Cannot reconnect: %s", err->message);
514		g_dbus_send_message(dc_data->conn, reply);
515
516		/* Send abort request because remote side */
517		/* is now in PENDING state */
518		if (!mcap_mdl_abort(chan->mdl, abort_mdl_cb, NULL, NULL,
519								&gerr)) {
520			error("%s", gerr->message);
521			g_error_free(gerr);
522		}
523		return;
524	}
525
526	fd = mcap_mdl_get_fd(dc_data->hdp_chann->mdl);
527	if (fd < 0) {
528		reply = g_dbus_create_error(dc_data->msg,
529						ERROR_INTERFACE ".HealthError",
530						"Cannot get file descriptor");
531		g_dbus_send_message(dc_data->conn, reply);
532		return;
533	}
534
535	reply = g_dbus_create_reply(dc_data->msg, DBUS_TYPE_UNIX_FD,
536							&fd, DBUS_TYPE_INVALID);
537	g_dbus_send_message(dc_data->conn, reply);
538
539	g_dbus_emit_signal(dc_data->conn,
540			device_get_path(dc_data->hdp_chann->dev->dev),
541			HEALTH_DEVICE, "ChannelConnected",
542			DBUS_TYPE_OBJECT_PATH, &dc_data->hdp_chann->path,
543			DBUS_TYPE_INVALID);
544}
545
546static void hdp_get_dcpsm_cb(uint16_t dcpsm, gpointer user_data, GError *err)
547{
548	struct hdp_tmp_dc_data *hdp_conn = user_data;
549	struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
550	GError *gerr = NULL;
551	uint8_t mode;
552
553	if (err) {
554		hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
555		return;
556	}
557
558	if (hdp_chann->config == HDP_RELIABLE_DC)
559		mode = L2CAP_MODE_ERTM;
560	else
561		mode = L2CAP_MODE_STREAMING;
562
563	if (mcap_connect_mdl(hdp_chann->mdl, mode, dcpsm, hdp_conn->cb,
564					hdp_tmp_dc_data_ref(hdp_conn),
565					hdp_tmp_dc_data_destroy, &gerr))
566		return;
567
568	hdp_tmp_dc_data_unref(hdp_conn);
569	hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
570	g_error_free(gerr);
571	gerr = NULL;
572}
573
574static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
575								gpointer data)
576{
577	struct hdp_tmp_dc_data *dc_data = data;
578	GError *gerr = NULL;
579	DBusMessage *reply;
580
581	if (err) {
582		reply = g_dbus_create_error(dc_data->msg,
583					ERROR_INTERFACE ".HealthError",
584					"Cannot reconnect: %s", err->message);
585		g_dbus_send_message(dc_data->conn, reply);
586		return;
587	}
588
589	dc_data->cb = hdp_mdl_reconn_cb;
590
591	if (hdp_get_dcpsm(dc_data->hdp_chann->dev, hdp_get_dcpsm_cb,
592					hdp_tmp_dc_data_ref(dc_data),
593					hdp_tmp_dc_data_destroy, &gerr))
594		return;
595
596	error("%s", gerr->message);
597
598	reply = g_dbus_create_error(dc_data->msg,
599					ERROR_INTERFACE ".HealthError",
600					"Cannot reconnect: %s", gerr->message);
601	g_dbus_send_message(dc_data->conn, reply);
602	hdp_tmp_dc_data_unref(dc_data);
603	g_error_free(gerr);
604
605	/* Send abort request because remote side is now in PENDING state */
606	if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) {
607		error("%s", gerr->message);
608		g_error_free(gerr);
609	}
610}
611
612static DBusMessage *channel_acquire_continue(struct hdp_tmp_dc_data *data,
613								GError *err)
614{
615	DBusMessage *reply;
616	GError *gerr = NULL;
617	int fd;
618
619	if (err) {
620		return g_dbus_create_error(data->msg,
621						ERROR_INTERFACE ".HealthError",
622						"%s", err->message);
623	}
624
625	fd = mcap_mdl_get_fd(data->hdp_chann->mdl);
626	if (fd >= 0)
627		return g_dbus_create_reply(data->msg, DBUS_TYPE_UNIX_FD, &fd,
628							DBUS_TYPE_INVALID);
629
630	hdp_tmp_dc_data_ref(data);
631	if (mcap_reconnect_mdl(data->hdp_chann->mdl, device_reconnect_mdl_cb,
632					data, hdp_tmp_dc_data_destroy, &gerr))
633		return NULL;
634
635	hdp_tmp_dc_data_unref(data);
636	reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
637					"Cannot reconnect: %s", gerr->message);
638	g_error_free(gerr);
639
640	return reply;
641}
642
643static void channel_acquire_cb(gpointer data, GError *err)
644{
645	struct hdp_tmp_dc_data *dc_data = data;
646	DBusMessage *reply;
647
648	reply = channel_acquire_continue(data, err);
649
650	if (reply)
651		g_dbus_send_message(dc_data->conn, reply);
652}
653
654static DBusMessage *channel_acquire(DBusConnection *conn,
655					DBusMessage *msg, void *user_data)
656{
657	struct hdp_channel *chan = user_data;
658	struct hdp_tmp_dc_data *dc_data;
659	GError *gerr = NULL;
660	DBusMessage *reply;
661
662	dc_data = g_new0(struct hdp_tmp_dc_data, 1);
663	dc_data->conn = dbus_connection_ref(conn);
664	dc_data->msg = dbus_message_ref(msg);
665	dc_data->hdp_chann = hdp_channel_ref(chan);
666
667	if (chan->dev->mcl_conn) {
668		reply = channel_acquire_continue(hdp_tmp_dc_data_ref(dc_data),
669									NULL);
670		hdp_tmp_dc_data_unref(dc_data);
671		return reply;
672	}
673
674	if (hdp_establish_mcl(chan->dev, channel_acquire_cb,
675						hdp_tmp_dc_data_ref(dc_data),
676						hdp_tmp_dc_data_destroy, &gerr))
677		return NULL;
678
679	reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
680					"%s", gerr->message);
681	hdp_tmp_dc_data_unref(dc_data);
682	g_error_free(gerr);
683
684	return reply;
685}
686
687static void close_mdl(struct hdp_channel *hdp_chann)
688{
689	int fd;
690
691	fd = mcap_mdl_get_fd(hdp_chann->mdl);
692	if (fd < 0)
693		return;
694
695	close(fd);
696}
697
698static DBusMessage *channel_release(DBusConnection *conn,
699					DBusMessage *msg, void *user_data)
700{
701	struct hdp_channel *hdp_chann = user_data;
702
703	close_mdl(hdp_chann);
704
705	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
706}
707
708static void free_echo_data(struct hdp_echo_data *edata)
709{
710	if (!edata)
711		return;
712
713	if (edata->tid)
714		g_source_remove(edata->tid);
715
716	if (edata->buf)
717		g_free(edata->buf);
718
719
720	g_free(edata);
721}
722
723static void health_channel_destroy(void *data)
724{
725	struct hdp_channel *hdp_chan = data;
726	struct hdp_device *dev = hdp_chan->dev;
727
728	DBG("Destroy Health Channel %s", hdp_chan->path);
729	if (!g_slist_find(dev->channels, hdp_chan))
730		goto end;
731
732	dev->channels = g_slist_remove(dev->channels, hdp_chan);
733
734	if (hdp_chan->mdep != HDP_MDEP_ECHO)
735		g_dbus_emit_signal(dev->conn, device_get_path(dev->dev),
736					HEALTH_DEVICE, "ChannelDeleted",
737					DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
738					DBUS_TYPE_INVALID);
739
740	if (hdp_chan == dev->fr) {
741		char *empty_path;
742
743		hdp_channel_unref(dev->fr);
744		dev->fr = NULL;
745		empty_path = "/";
746		emit_property_changed(dev->conn, device_get_path(dev->dev),
747					HEALTH_DEVICE, "MainChannel",
748					DBUS_TYPE_OBJECT_PATH, &empty_path);
749	}
750
751end:
752	hdp_channel_unref(hdp_chan);
753}
754
755static GDBusMethodTable health_channels_methods[] = {
756	{"GetProperties","",	"a{sv}",	channel_get_properties },
757	{"Acquire",	"",	"h",		channel_acquire,
758						G_DBUS_METHOD_FLAG_ASYNC },
759	{"Release",	"",	"",		channel_release },
760	{ NULL }
761};
762
763static struct hdp_channel *create_channel(struct hdp_device *dev,
764						uint8_t config,
765						struct mcap_mdl *mdl,
766						uint16_t mdlid,
767						struct hdp_application *app,
768						GError **err)
769{
770	struct hdp_channel *hdp_chann;
771
772	if (!dev)
773		return NULL;
774
775	hdp_chann = g_new0(struct hdp_channel, 1);
776	hdp_chann->config = config;
777	hdp_chann->dev = health_device_ref(dev);
778	hdp_chann->mdlid = mdlid;
779
780	if (mdl)
781		hdp_chann->mdl = mcap_mdl_ref(mdl);
782
783	if (app) {
784		hdp_chann->mdep = app->id;
785		hdp_chann->app = hdp_application_ref(app);
786	} else
787		hdp_chann->edata = g_new0(struct hdp_echo_data, 1);
788
789	hdp_chann->path = g_strdup_printf("%s/chan%d",
790					device_get_path(hdp_chann->dev->dev),
791					hdp_chann->mdlid);
792
793	dev->channels = g_slist_append(dev->channels,
794						hdp_channel_ref(hdp_chann));
795
796	if (hdp_chann->mdep == HDP_MDEP_ECHO)
797		return hdp_channel_ref(hdp_chann);
798
799	if (!g_dbus_register_interface(dev->conn, hdp_chann->path,
800					HEALTH_CHANNEL,
801					health_channels_methods, NULL, NULL,
802					hdp_chann, health_channel_destroy)) {
803		g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
804					"Can't register the channel interface");
805		health_channel_destroy(hdp_chann);
806		return NULL;
807	}
808
809	return hdp_channel_ref(hdp_chann);
810}
811
812static void remove_channels(struct hdp_device *dev)
813{
814	struct hdp_channel *chan;
815	char *path;
816
817	while (dev->channels) {
818		chan = dev->channels->data;
819
820		path = g_strdup(chan->path);
821		if (!g_dbus_unregister_interface(dev->conn, path,
822								HEALTH_CHANNEL))
823			health_channel_destroy(chan);
824		g_free(path);
825	}
826}
827
828static void close_device_con(struct hdp_device *dev, gboolean cache)
829{
830	if (!dev->mcl)
831		return;
832
833	mcap_close_mcl(dev->mcl, cache);
834	dev->mcl_conn = FALSE;
835
836	if (cache)
837		return;
838
839	device_unref_mcl(dev);
840	remove_channels(dev);
841
842	if (!dev->sdp_present) {
843		const char *path;
844
845		path = device_get_path(dev->dev);
846		g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE);
847	}
848}
849
850static int send_echo_data(int sock, const void *buf, uint32_t size)
851{
852	const uint8_t *buf_b = buf;
853	uint32_t sent = 0;
854
855	while (sent < size) {
856		int n = write(sock, buf_b + sent, size - sent);
857		if (n < 0)
858			return -1;
859		sent += n;
860	}
861
862	return 0;
863}
864
865static gboolean serve_echo(GIOChannel *io_chan, GIOCondition cond,
866								gpointer data)
867{
868	struct hdp_channel *chan = data;
869	uint8_t buf[MCAP_DC_MTU];
870	int fd, len;
871
872	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
873		hdp_channel_unref(chan);
874		return FALSE;
875	}
876
877	if (chan->edata->echo_done)
878		goto fail;
879
880	chan->edata->echo_done = TRUE;
881
882	fd = g_io_channel_unix_get_fd(io_chan);
883	len = read(fd, buf, sizeof(buf));
884
885	if (send_echo_data(fd, buf, len)  >= 0)
886		return TRUE;
887
888fail:
889	close_device_con(chan->dev, FALSE);
890	hdp_channel_unref(chan);
891	return FALSE;
892}
893
894static gboolean check_channel_conf(struct hdp_channel *chan)
895{
896	GError *err = NULL;
897	GIOChannel *io;
898	uint8_t mode;
899	uint16_t imtu, omtu;
900	int fd;
901
902	fd = mcap_mdl_get_fd(chan->mdl);
903	if (fd < 0)
904		return FALSE;
905	io = g_io_channel_unix_new(fd);
906
907	if (!bt_io_get(io, BT_IO_L2CAP, &err,
908			BT_IO_OPT_MODE, &mode,
909			BT_IO_OPT_IMTU, &imtu,
910			BT_IO_OPT_OMTU, &omtu,
911			BT_IO_OPT_INVALID)) {
912		error("Error: %s", err->message);
913		g_io_channel_unref(io);
914		g_error_free(err);
915		return FALSE;
916	}
917
918	g_io_channel_unref(io);
919
920	switch (chan->config) {
921	case HDP_RELIABLE_DC:
922		if (mode != L2CAP_MODE_ERTM)
923			return FALSE;
924		break;
925	case HDP_STREAMING_DC:
926		if (mode != L2CAP_MODE_STREAMING)
927			return FALSE;
928		break;
929	default:
930		error("Error: Connected with unknown configuration");
931		return FALSE;
932	}
933
934	DBG("MDL imtu %d omtu %d Channel imtu %d omtu %d", imtu, omtu,
935						chan->imtu, chan->omtu);
936
937	if (!chan->imtu)
938		chan->imtu = imtu;
939	if (!chan->omtu)
940		chan->omtu = omtu;
941
942	if (chan->imtu != imtu || chan->omtu != omtu)
943		return FALSE;
944
945	return TRUE;
946}
947
948static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
949{
950	struct hdp_device *dev = data;
951	struct hdp_channel *chan;
952
953	DBG("hdp_mcap_mdl_connected_cb");
954	if (!dev->ndc)
955		return;
956
957	chan = dev->ndc;
958	if (!chan->mdl)
959		chan->mdl = mcap_mdl_ref(mdl);
960
961	if (!g_slist_find(dev->channels, chan))
962		dev->channels = g_slist_prepend(dev->channels,
963							hdp_channel_ref(chan));
964
965	if (!check_channel_conf(chan)) {
966		close_mdl(chan);
967		goto end;
968	}
969
970	if (chan->mdep == HDP_MDEP_ECHO) {
971		GIOChannel *io;
972		int fd;
973
974		fd = mcap_mdl_get_fd(chan->mdl);
975		if (fd < 0)
976			goto end;
977
978		chan->edata->echo_done = FALSE;
979		io = g_io_channel_unix_new(fd);
980		g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
981				serve_echo, hdp_channel_ref(chan));
982		g_io_channel_unref(io);
983		goto end;
984	}
985
986	g_dbus_emit_signal(dev->conn, device_get_path(dev->dev), HEALTH_DEVICE,
987					"ChannelConnected",
988					DBUS_TYPE_OBJECT_PATH, &chan->path,
989					DBUS_TYPE_INVALID);
990
991	if (dev->fr)
992		goto end;
993
994	dev->fr = hdp_channel_ref(chan);
995
996	emit_property_changed(dev->conn, device_get_path(dev->dev),
997					HEALTH_DEVICE, "MainChannel",
998					DBUS_TYPE_OBJECT_PATH, &dev->fr->path);
999
1000end:
1001	hdp_channel_unref(dev->ndc);
1002	dev->ndc = NULL;
1003}
1004
1005static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
1006{
1007	/* struct hdp_device *dev = data; */
1008
1009	DBG("hdp_mcap_mdl_closed_cb");
1010
1011	/* Nothing to do */
1012}
1013
1014static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
1015{
1016	struct hdp_device *dev = data;
1017	struct hdp_channel *chan;
1018	char *path;
1019	GSList *l;
1020
1021	DBG("hdp_mcap_mdl_deleted_cb");
1022	l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1023	if (!l)
1024		return;
1025
1026	chan = l->data;
1027
1028	path = g_strdup(chan->path);
1029	if (!g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL))
1030		health_channel_destroy(chan);
1031	g_free(path);
1032}
1033
1034static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
1035{
1036	struct hdp_device *dev = data;
1037
1038	DBG("hdp_mcap_mdl_aborted_cb");
1039	if (!dev->ndc)
1040		return;
1041
1042	dev->ndc->mdl = mcap_mdl_ref(mdl);
1043
1044	if (!g_slist_find(dev->channels, dev->ndc))
1045		dev->channels = g_slist_prepend(dev->channels,
1046						hdp_channel_ref(dev->ndc));
1047
1048	if (dev->ndc->mdep != HDP_MDEP_ECHO)
1049		g_dbus_emit_signal(dev->conn, device_get_path(dev->dev),
1050					HEALTH_DEVICE, "ChannelConnected",
1051					DBUS_TYPE_OBJECT_PATH, &dev->ndc->path,
1052					DBUS_TYPE_INVALID);
1053
1054	hdp_channel_unref(dev->ndc);
1055	dev->ndc = NULL;
1056}
1057
1058static uint8_t hdp2l2cap_mode(uint8_t hdp_mode)
1059{
1060	return hdp_mode == HDP_STREAMING_DC ? L2CAP_MODE_STREAMING :
1061								L2CAP_MODE_ERTM;
1062}
1063
1064static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
1065				uint16_t mdlid, uint8_t *conf, void *data)
1066{
1067	struct hdp_device *dev = data;
1068	struct hdp_application *app;
1069	GError *err = NULL;
1070	GSList *l;
1071
1072	DBG("Data channel request");
1073
1074	if (mdepid == HDP_MDEP_ECHO) {
1075		switch (*conf) {
1076		case HDP_NO_PREFERENCE_DC:
1077			*conf = HDP_RELIABLE_DC;
1078		case HDP_RELIABLE_DC:
1079			break;
1080		case HDP_STREAMING_DC:
1081			return MCAP_CONFIGURATION_REJECTED;
1082		default:
1083			/* Special case defined in HDP spec 3.4. When an invalid
1084			* configuration is received we shall close the MCL when
1085			* we are still processing the callback. */
1086			close_device_con(dev, FALSE);
1087			return MCAP_CONFIGURATION_REJECTED; /* not processed */
1088		}
1089
1090		if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1091						L2CAP_MODE_ERTM, &err)) {
1092			error("Error: %s", err->message);
1093			g_error_free(err);
1094			return MCAP_MDL_BUSY;
1095		}
1096
1097		dev->ndc = create_channel(dev, *conf, NULL, mdlid, NULL, NULL);
1098		if (!dev->ndc)
1099			return MCAP_MDL_BUSY;
1100
1101		return MCAP_SUCCESS;
1102	}
1103
1104	l = g_slist_find_custom(applications, &mdepid, cmp_app_id);
1105	if (!l)
1106		return MCAP_INVALID_MDEP;
1107
1108	app = l->data;
1109
1110	/* Check if is the first dc if so,
1111	* only reliable configuration is allowed */
1112	switch (*conf) {
1113	case HDP_NO_PREFERENCE_DC:
1114		if (app->role == HDP_SINK)
1115			return MCAP_CONFIGURATION_REJECTED;
1116		else if (dev->fr && app->chan_type_set)
1117			*conf = app->chan_type;
1118		else
1119			*conf = HDP_RELIABLE_DC;
1120		break;
1121	case HDP_STREAMING_DC:
1122		if (!dev->fr || app->role == HDP_SOURCE)
1123			return MCAP_CONFIGURATION_REJECTED;
1124	case HDP_RELIABLE_DC:
1125		if (app->role == HDP_SOURCE)
1126			return MCAP_CONFIGURATION_REJECTED;
1127		break;
1128	default:
1129		/* Special case defined in HDP spec 3.4. When an invalid
1130		* configuration is received we shall close the MCL when
1131		* we are still processing the callback. */
1132		close_device_con(dev, FALSE);
1133		return MCAP_CONFIGURATION_REJECTED; /* not processed */
1134	}
1135
1136	l = g_slist_find_custom(dev->channels, &mdlid, cmp_chan_mdlid);
1137	if (l) {
1138		struct hdp_channel *chan = l->data;
1139		char *path;
1140
1141		path = g_strdup(chan->path);
1142		g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL);
1143		g_free(path);
1144	}
1145
1146	if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1147						hdp2l2cap_mode(*conf), &err)) {
1148		error("Error: %s", err->message);
1149		g_error_free(err);
1150		return MCAP_MDL_BUSY;
1151	}
1152
1153	dev->ndc = create_channel(dev, *conf, NULL, mdlid, app, NULL);
1154	if (!dev->ndc)
1155		return MCAP_MDL_BUSY;
1156
1157	return MCAP_SUCCESS;
1158}
1159
1160static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
1161{
1162	struct hdp_device *dev = data;
1163	struct hdp_channel *chan;
1164	GError *err = NULL;
1165	GSList *l;
1166
1167	l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1168	if (!l)
1169		return MCAP_INVALID_MDL;
1170
1171	chan = l->data;
1172
1173	if (!dev->fr && (chan->config != HDP_RELIABLE_DC) &&
1174						(chan->mdep != HDP_MDEP_ECHO))
1175		return MCAP_UNSPECIFIED_ERROR;
1176
1177	if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1178					hdp2l2cap_mode(chan->config), &err)) {
1179		error("Error: %s", err->message);
1180		g_error_free(err);
1181		return MCAP_MDL_BUSY;
1182	}
1183
1184	dev->ndc = hdp_channel_ref(chan);
1185
1186	return MCAP_SUCCESS;
1187}
1188
1189gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err)
1190{
1191	gboolean ret;
1192
1193	if (!device->mcl)
1194		return FALSE;
1195
1196	ret = mcap_mcl_set_cb(device->mcl, device, err,
1197		MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
1198		MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
1199		MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
1200		MCAP_MDL_CB_ABORTED, hdp_mcap_mdl_aborted_cb,
1201		MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
1202		MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
1203		MCAP_MDL_CB_INVALID);
1204
1205	if (ret)
1206		return TRUE;
1207
1208	error("Can't set mcl callbacks, closing mcl");
1209	close_device_con(device, TRUE);
1210
1211	return FALSE;
1212}
1213
1214static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
1215{
1216	struct hdp_device *hdp_device;
1217	bdaddr_t addr;
1218	GSList *l;
1219
1220	mcap_mcl_get_addr(mcl, &addr);
1221	l = g_slist_find_custom(devices, &addr, cmp_dev_addr);
1222	if (!l) {
1223		struct hdp_adapter *hdp_adapter = data;
1224		struct btd_device *device;
1225		char str[18];
1226
1227		ba2str(&addr, str);
1228		device = adapter_get_device(connection,
1229					hdp_adapter->btd_adapter, str);
1230		if (!device)
1231			return;
1232		hdp_device = create_health_device(connection, device);
1233		if (!hdp_device)
1234			return;
1235		devices = g_slist_append(devices, hdp_device);
1236	} else
1237		hdp_device = l->data;
1238
1239	hdp_device->mcl = mcap_mcl_ref(mcl);
1240	hdp_device->mcl_conn = TRUE;
1241
1242	DBG("New mcl connected from  %s", device_get_path(hdp_device->dev));
1243
1244	hdp_set_mcl_cb(hdp_device, NULL);
1245}
1246
1247static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
1248{
1249	struct hdp_device *hdp_device;
1250	GSList *l;
1251
1252	l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1253	if (!l)
1254		return;
1255
1256	hdp_device = l->data;
1257	hdp_device->mcl_conn = TRUE;
1258
1259	DBG("MCL reconnected %s", device_get_path(hdp_device->dev));
1260
1261	hdp_set_mcl_cb(hdp_device, NULL);
1262}
1263
1264static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
1265{
1266	struct hdp_device *hdp_device;
1267	GSList *l;
1268
1269	l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1270	if (!l)
1271		return;
1272
1273	hdp_device = l->data;
1274	hdp_device->mcl_conn = FALSE;
1275
1276	DBG("Mcl disconnected %s", device_get_path(hdp_device->dev));
1277}
1278
1279static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
1280{
1281	struct hdp_device *hdp_device;
1282	const char *path;
1283	GSList *l;
1284
1285	l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1286	if (!l)
1287		return;
1288
1289	hdp_device = l->data;
1290	device_unref_mcl(hdp_device);
1291
1292	if (hdp_device->sdp_present)
1293		return;
1294
1295	/* Because remote device hasn't announced an HDP record */
1296	/* the Bluetooth daemon won't notify when the device shall */
1297	/* be removed. Then we have to remove the HealthDevice */
1298	/* interface manually */
1299	path = device_get_path(hdp_device->dev);
1300	g_dbus_unregister_interface(hdp_device->conn, path, HEALTH_DEVICE);
1301	DBG("Mcl uncached %s", path);
1302}
1303
1304static void check_devices_mcl(void)
1305{
1306	struct hdp_device *dev;
1307	GSList *l, *to_delete = NULL;
1308
1309	for (l = devices; l; l = l->next) {
1310		dev = l->data;
1311		device_unref_mcl(dev);
1312
1313		if (!dev->sdp_present)
1314			to_delete = g_slist_append(to_delete, dev);
1315		else
1316			remove_channels(dev);
1317	}
1318
1319	for (l = to_delete; l; l = l->next) {
1320		const char *path;
1321
1322		path = device_get_path(dev->dev);
1323		g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE);
1324	}
1325
1326	g_slist_free(to_delete);
1327}
1328
1329static void release_adapter_instance(struct hdp_adapter *hdp_adapter)
1330{
1331	if (!hdp_adapter->mi)
1332		return;
1333
1334	check_devices_mcl();
1335	mcap_release_instance(hdp_adapter->mi);
1336	mcap_instance_unref(hdp_adapter->mi);
1337	hdp_adapter->mi = NULL;
1338}
1339
1340static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
1341{
1342	GError *err = NULL;
1343	bdaddr_t addr;
1344
1345	if (!applications) {
1346		release_adapter_instance(hdp_adapter);
1347		goto update;
1348	}
1349
1350	if (hdp_adapter->mi)
1351		goto update;
1352
1353	adapter_get_address(hdp_adapter->btd_adapter, &addr);
1354	hdp_adapter->mi = mcap_create_instance(&addr, BT_IO_SEC_MEDIUM, 0, 0,
1355					mcl_connected, mcl_reconnected,
1356					mcl_disconnected, mcl_uncached,
1357					NULL, /* CSP is not used by now */
1358					hdp_adapter, &err);
1359
1360	if (!hdp_adapter->mi) {
1361		error("Error creating the MCAP instance: %s", err->message);
1362		g_error_free(err);
1363		return FALSE;
1364	}
1365
1366	hdp_adapter->ccpsm = mcap_get_ctrl_psm(hdp_adapter->mi, &err);
1367	if (err) {
1368		error("Error getting MCAP control PSM: %s", err->message);
1369		goto fail;
1370	}
1371
1372	hdp_adapter->dcpsm = mcap_get_data_psm(hdp_adapter->mi, &err);
1373	if (err) {
1374		error("Error getting MCAP data PSM: %s", err->message);
1375		goto fail;
1376	}
1377
1378update:
1379	if (hdp_update_sdp_record(hdp_adapter, applications))
1380		return TRUE;
1381	error("Error updating the SDP record");
1382
1383fail:
1384	release_adapter_instance(hdp_adapter);
1385	if (err)
1386		g_error_free(err);
1387	return FALSE;
1388}
1389
1390int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *adapter)
1391{
1392	struct hdp_adapter *hdp_adapter;
1393
1394	hdp_adapter = g_new0(struct hdp_adapter, 1);
1395	hdp_adapter->btd_adapter = btd_adapter_ref(adapter);
1396
1397	if(!update_adapter(hdp_adapter))
1398		goto fail;
1399
1400	adapters = g_slist_append(adapters, hdp_adapter);
1401
1402	return 0;
1403
1404fail:
1405	btd_adapter_unref(hdp_adapter->btd_adapter);
1406	g_free(hdp_adapter);
1407	return -1;
1408}
1409
1410void hdp_adapter_unregister(struct btd_adapter *adapter)
1411{
1412	struct hdp_adapter *hdp_adapter;
1413	GSList *l;
1414
1415	l = g_slist_find_custom(adapters, adapter, cmp_adapter);
1416
1417	if (!l)
1418		return;
1419
1420	hdp_adapter = l->data;
1421	adapters = g_slist_remove(adapters, hdp_adapter);
1422	if (hdp_adapter->sdp_handler)
1423		remove_record_from_server(hdp_adapter->sdp_handler);
1424	release_adapter_instance(hdp_adapter);
1425	btd_adapter_unref(hdp_adapter->btd_adapter);
1426	g_free(hdp_adapter);
1427}
1428
1429static void delete_echo_channel_cb(GError *err, gpointer chan)
1430{
1431	if (err && err->code != MCAP_INVALID_MDL) {
1432		/* TODO: Decide if more action is required here */
1433		error("Error deleting echo channel: %s", err->message);
1434		return;
1435	}
1436
1437	health_channel_destroy(chan);
1438}
1439
1440static void delete_echo_channel(struct hdp_channel *chan)
1441{
1442	GError *err = NULL;
1443
1444	if (!chan->dev->mcl_conn) {
1445		error("Echo channel cannot be deleted: mcl closed");
1446		return;
1447	}
1448
1449	if (mcap_delete_mdl(chan->mdl, delete_echo_channel_cb,
1450				hdp_channel_ref(chan),
1451				(GDestroyNotify) hdp_channel_unref, &err))
1452		return;
1453
1454	hdp_channel_unref(chan);
1455	error("Error deleting the echo channel: %s", err->message);
1456	g_error_free(err);
1457
1458	/* TODO: Decide if more action is required here */
1459}
1460
1461static void abort_echo_channel_cb(GError *err, gpointer data)
1462{
1463	struct hdp_channel *chan = data;
1464
1465	if (err && err->code != MCAP_ERROR_INVALID_OPERATION) {
1466		error("Aborting error: %s", err->message);
1467		if (err->code == MCAP_INVALID_MDL) {
1468			/* MDL is removed from MCAP so we can */
1469			/* free the data channel without sending */
1470			/* a MD_DELETE_MDL_REQ */
1471			/* TODO review the above comment */
1472			/* hdp_channel_unref(chan); */
1473		}
1474		return;
1475	}
1476
1477	delete_echo_channel(chan);
1478}
1479
1480static void destroy_create_dc_data(gpointer data)
1481{
1482	struct hdp_create_dc *dc_data = data;
1483
1484	hdp_create_data_unref(dc_data);
1485}
1486
1487static void *generate_echo_packet(void)
1488{
1489	uint8_t *buf;
1490	int i;
1491
1492	buf = g_malloc(HDP_ECHO_LEN);
1493	srand(time(NULL));
1494
1495	for(i = 0; i < HDP_ECHO_LEN; i++)
1496		buf[i] = rand() % UINT8_MAX;
1497
1498	return buf;
1499}
1500
1501static gboolean check_echo(GIOChannel *io_chan, GIOCondition cond,
1502								gpointer data)
1503{
1504	struct hdp_tmp_dc_data *hdp_conn =  data;
1505	struct hdp_echo_data *edata = hdp_conn->hdp_chann->edata;
1506	struct hdp_channel *chan = hdp_conn->hdp_chann;
1507	uint8_t buf[MCAP_DC_MTU];
1508	DBusMessage *reply;
1509	gboolean value;
1510	int fd, len;
1511
1512	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
1513		value = FALSE;
1514		goto end;
1515	}
1516
1517	fd = g_io_channel_unix_get_fd(io_chan);
1518	len = read(fd, buf, sizeof(buf));
1519
1520	if (len != HDP_ECHO_LEN) {
1521		value = FALSE;
1522		goto end;
1523	}
1524
1525	value = (memcmp(buf, edata->buf, len) == 0);
1526
1527end:
1528	reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_BOOLEAN, &value,
1529							DBUS_TYPE_INVALID);
1530	g_dbus_send_message(hdp_conn->conn, reply);
1531	g_source_remove(edata->tid);
1532	edata->tid = 0;
1533	g_free(edata->buf);
1534	edata->buf = NULL;
1535
1536	if (!value)
1537		close_device_con(chan->dev, FALSE);
1538	else
1539		delete_echo_channel(chan);
1540	hdp_tmp_dc_data_unref(hdp_conn);
1541
1542	return FALSE;
1543}
1544
1545static gboolean echo_timeout(gpointer data)
1546{
1547	struct hdp_channel *chan = data;
1548	GIOChannel *io;
1549	int fd;
1550
1551	error("Error: Echo request timeout");
1552	chan->edata->tid = 0;
1553
1554	fd = mcap_mdl_get_fd(chan->mdl);
1555	if (fd < 0)
1556		return FALSE;
1557
1558	io = g_io_channel_unix_new(fd);
1559	g_io_channel_shutdown(io, TRUE, NULL);
1560
1561	return FALSE;
1562}
1563
1564static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
1565								gpointer data)
1566{
1567	struct hdp_tmp_dc_data *hdp_conn =  data;
1568	struct hdp_echo_data *edata;
1569	GError *gerr = NULL;
1570	DBusMessage *reply;
1571	GIOChannel *io;
1572	int fd;
1573
1574	if (err) {
1575		reply = g_dbus_create_error(hdp_conn->msg,
1576						ERROR_INTERFACE ".HealthError",
1577						"%s", err->message);
1578		g_dbus_send_message(hdp_conn->conn, reply);
1579
1580		/* Send abort request because remote */
1581		/* side is now in PENDING state. */
1582		if (!mcap_mdl_abort(hdp_conn->hdp_chann->mdl,
1583					abort_echo_channel_cb,
1584					hdp_channel_ref(hdp_conn->hdp_chann),
1585					(GDestroyNotify) hdp_channel_unref,
1586					&gerr)) {
1587			error("%s", gerr->message);
1588			g_error_free(gerr);
1589			hdp_channel_unref(hdp_conn->hdp_chann);
1590		}
1591		return;
1592	}
1593
1594	fd = mcap_mdl_get_fd(hdp_conn->hdp_chann->mdl);
1595	if (fd < 0) {
1596		reply = g_dbus_create_error(hdp_conn->msg,
1597						ERROR_INTERFACE ".HealthError",
1598						"Can't write in echo channel");
1599		g_dbus_send_message(hdp_conn->conn, reply);
1600		delete_echo_channel(hdp_conn->hdp_chann);
1601		return;
1602	}
1603
1604	edata = hdp_conn->hdp_chann->edata;
1605	edata->buf = generate_echo_packet();
1606	send_echo_data(fd, edata->buf, HDP_ECHO_LEN);
1607
1608	io = g_io_channel_unix_new(fd);
1609	g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
1610			check_echo, hdp_tmp_dc_data_ref(hdp_conn));
1611
1612	edata->tid  = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
1613					ECHO_TIMEOUT, echo_timeout,
1614					hdp_channel_ref(hdp_conn->hdp_chann),
1615					(GDestroyNotify) hdp_channel_unref);
1616
1617	g_io_channel_unref(io);
1618}
1619
1620static void delete_mdl_cb(GError *err, gpointer data)
1621{
1622	if (err)
1623		error("Deleting error: %s", err->message);
1624}
1625
1626static void abort_and_del_mdl_cb(GError *err, gpointer data)
1627{
1628	struct mcap_mdl *mdl = data;
1629	GError *gerr = NULL;
1630
1631	if (err) {
1632		error("%s", err->message);
1633		if (err->code == MCAP_INVALID_MDL) {
1634			/* MDL is removed from MCAP so we don't */
1635			/* need to delete it. */
1636			return;
1637		}
1638	}
1639
1640	if (!mcap_delete_mdl(mdl, delete_mdl_cb, NULL, NULL, &gerr)) {
1641		error("%s", gerr->message);
1642		g_error_free(gerr);
1643	}
1644}
1645
1646static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
1647{
1648	struct hdp_tmp_dc_data *hdp_conn =  data;
1649	struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1650	struct hdp_device *dev = hdp_chann->dev;
1651	DBusMessage *reply;
1652	GError *gerr = NULL;
1653
1654	if (err) {
1655		error("%s", err->message);
1656		reply = g_dbus_create_reply(hdp_conn->msg,
1657					DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1658					DBUS_TYPE_INVALID);
1659		g_dbus_send_message(hdp_conn->conn, reply);
1660
1661		/* Send abort request because remote side */
1662		/* is now in PENDING state */
1663		if (!mcap_mdl_abort(hdp_chann->mdl, abort_mdl_cb, hdp_chann,
1664								NULL, &gerr)) {
1665			error("%s", gerr->message);
1666			g_error_free(gerr);
1667		}
1668		return;
1669	}
1670
1671	reply = g_dbus_create_reply(hdp_conn->msg,
1672					DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1673					DBUS_TYPE_INVALID);
1674	g_dbus_send_message(hdp_conn->conn, reply);
1675
1676	if (!check_channel_conf(hdp_chann)) {
1677		close_mdl(hdp_chann);
1678		return;
1679	}
1680
1681	if (dev->fr)
1682		return;
1683
1684	dev->fr = hdp_channel_ref(hdp_chann);
1685
1686	if (dev->fr->mdep != HDP_MDEP_ECHO)
1687		g_dbus_emit_signal(dev->conn,
1688					device_get_path(dev->dev),
1689					HEALTH_DEVICE,
1690					"ChannelConnected",
1691					DBUS_TYPE_OBJECT_PATH, &dev->fr->path,
1692					DBUS_TYPE_INVALID);
1693
1694
1695	emit_property_changed(dev->conn, device_get_path(dev->dev),
1696					HEALTH_DEVICE, "MainChannel",
1697					DBUS_TYPE_OBJECT_PATH, &dev->fr->path);
1698}
1699
1700static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
1701						GError *err, gpointer data)
1702{
1703	struct hdp_create_dc *user_data = data;
1704	struct hdp_tmp_dc_data *hdp_conn;
1705	struct hdp_channel *hdp_chan;
1706	GError *gerr = NULL;
1707	DBusMessage *reply;
1708
1709	if (err) {
1710		reply = g_dbus_create_error(user_data->msg,
1711					ERROR_INTERFACE ".HealthError",
1712					"%s", err->message);
1713		g_dbus_send_message(user_data->conn, reply);
1714		return;
1715	}
1716
1717	if (user_data->mdep != HDP_MDEP_ECHO &&
1718				user_data->config == HDP_NO_PREFERENCE_DC) {
1719		if (!user_data->dev->fr && (conf != HDP_RELIABLE_DC)) {
1720			g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1721					"Data channel aborted, first data "
1722					"channel should be reliable");
1723			goto fail;
1724		} else if (conf == HDP_NO_PREFERENCE_DC ||
1725						conf > HDP_STREAMING_DC) {
1726			g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1727							"Data channel aborted, "
1728							"configuration error");
1729			goto fail;
1730		}
1731	}
1732
1733	hdp_chan = create_channel(user_data->dev, conf, mdl,
1734							mcap_mdl_get_mdlid(mdl),
1735							user_data->app, &gerr);
1736	if (!hdp_chan)
1737		goto fail;
1738
1739	hdp_conn = g_new0(struct hdp_tmp_dc_data, 1);
1740	hdp_conn->msg = dbus_message_ref(user_data->msg);
1741	hdp_conn->conn = dbus_connection_ref(user_data->conn);
1742	hdp_conn->hdp_chann = hdp_chan;
1743	hdp_conn->cb = user_data->cb;
1744	hdp_chan->mdep = user_data->mdep;
1745
1746	if (hdp_get_dcpsm(hdp_chan->dev, hdp_get_dcpsm_cb,
1747						hdp_tmp_dc_data_ref(hdp_conn),
1748						hdp_tmp_dc_data_destroy, &gerr))
1749		return;
1750
1751	error("%s", gerr->message);
1752	g_error_free(gerr);
1753
1754	reply = g_dbus_create_reply(hdp_conn->msg,
1755					DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
1756					DBUS_TYPE_INVALID);
1757	g_dbus_send_message(hdp_conn->conn, reply);
1758	hdp_tmp_dc_data_unref(hdp_conn);
1759
1760	/* Send abort request because remote side is now in PENDING state */
1761	if (!mcap_mdl_abort(mdl, abort_mdl_cb, hdp_chan, NULL, &gerr)) {
1762		error("%s", gerr->message);
1763		g_error_free(gerr);
1764	}
1765
1766	return;
1767
1768fail:
1769	reply = g_dbus_create_error(user_data->msg,
1770						ERROR_INTERFACE ".HealthError",
1771						"%s", gerr->message);
1772	g_dbus_send_message(user_data->conn, reply);
1773	g_error_free(gerr);
1774
1775	/* Send abort request because remote side is now in PENDING */
1776	/* state. Then we have to delete it because we couldn't */
1777	/* register the HealthChannel interface */
1778	if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl), NULL,
1779								&gerr)) {
1780		error("%s", gerr->message);
1781		g_error_free(gerr);
1782		mcap_mdl_unref(mdl);
1783	}
1784}
1785
1786static void device_create_dc_cb(gpointer user_data, GError *err)
1787{
1788	struct hdp_create_dc *data = user_data;
1789	DBusMessage *reply;
1790	GError *gerr = NULL;
1791
1792	if (err) {
1793		reply = g_dbus_create_error(data->msg,
1794					ERROR_INTERFACE ".HealthError",
1795					"%s", err->message);
1796		g_dbus_send_message(data->conn, reply);
1797		return;
1798	}
1799
1800	if (!data->dev->mcl) {
1801		g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1802				"Mcl was closed");
1803		goto fail;
1804	}
1805
1806	hdp_create_data_ref(data);
1807
1808	if (mcap_create_mdl(data->dev->mcl, data->mdep, data->config,
1809						device_create_mdl_cb, data,
1810						destroy_create_dc_data, &gerr))
1811		return;
1812	hdp_create_data_unref(data);
1813
1814fail:
1815	reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
1816							"%s", gerr->message);
1817	g_error_free(gerr);
1818	g_dbus_send_message(data->conn, reply);
1819}
1820
1821static DBusMessage *device_echo(DBusConnection *conn,
1822					DBusMessage *msg, void *user_data)
1823{
1824	struct hdp_device *device = user_data;
1825	struct hdp_create_dc *data;
1826	DBusMessage *reply;
1827	GError *err = NULL;
1828
1829	data = g_new0(struct hdp_create_dc, 1);
1830	data->dev = health_device_ref(device);
1831	data->mdep = HDP_MDEP_ECHO;
1832	data->config = HDP_RELIABLE_DC;
1833	data->msg = dbus_message_ref(msg);
1834	data->conn = dbus_connection_ref(conn);
1835	data->cb = hdp_echo_connect_cb;
1836	hdp_create_data_ref(data);
1837
1838	if (device->mcl_conn && device->mcl) {
1839		if (mcap_create_mdl(device->mcl, data->mdep, data->config,
1840						device_create_mdl_cb, data,
1841						destroy_create_dc_data, &err))
1842			return NULL;
1843		goto fail;
1844	}
1845
1846	if (hdp_establish_mcl(data->dev, device_create_dc_cb,
1847					data, destroy_create_dc_data, &err))
1848		return NULL;
1849
1850fail:
1851	reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1852							"%s", err->message);
1853	g_error_free(err);
1854	hdp_create_data_unref(data);
1855	return reply;
1856}
1857
1858static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
1859{
1860	struct hdp_create_dc *dc_data, *user_data = data;
1861	DBusMessage *reply;
1862	GError *gerr = NULL;
1863
1864	if (err) {
1865		reply = g_dbus_create_error(user_data->msg,
1866						ERROR_INTERFACE ".HealthError",
1867						"%s", err->message);
1868		g_dbus_send_message(user_data->conn, reply);
1869		return;
1870	}
1871
1872	dc_data = hdp_create_data_ref(user_data);
1873	dc_data->mdep = mdep;
1874
1875	if (user_data->dev->mcl_conn) {
1876		device_create_dc_cb(dc_data, NULL);
1877		hdp_create_data_unref(dc_data);
1878		return;
1879	}
1880
1881	if (hdp_establish_mcl(dc_data->dev, device_create_dc_cb,
1882					dc_data, destroy_create_dc_data, &gerr))
1883		return;
1884
1885	reply = g_dbus_create_error(user_data->msg,
1886						ERROR_INTERFACE ".HealthError",
1887						"%s", gerr->message);
1888	hdp_create_data_unref(dc_data);
1889	g_error_free(gerr);
1890	g_dbus_send_message(user_data->conn, reply);
1891}
1892
1893static DBusMessage *device_create_channel(DBusConnection *conn,
1894					DBusMessage *msg, void *user_data)
1895{
1896	struct hdp_device *device = user_data;
1897	struct hdp_application *app;
1898	struct hdp_create_dc *data;
1899	char *app_path, *conf;
1900	DBusMessage *reply;
1901	GError *err = NULL;
1902	uint8_t config;
1903	GSList *l;
1904
1905	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &app_path,
1906							DBUS_TYPE_STRING, &conf,
1907							DBUS_TYPE_INVALID))
1908		return btd_error_invalid_args(msg);
1909
1910	l = g_slist_find_custom(applications, app_path, cmp_app);
1911	if (!l)
1912		return btd_error_invalid_args(msg);
1913
1914	app = l->data;
1915
1916	if (g_ascii_strcasecmp("Reliable", conf) == 0)
1917		config = HDP_RELIABLE_DC;
1918	else if (g_ascii_strcasecmp("Streaming", conf) == 0)
1919		config = HDP_STREAMING_DC;
1920	else if (g_ascii_strcasecmp("Any", conf) == 0)
1921		config = HDP_NO_PREFERENCE_DC;
1922	else
1923		return btd_error_invalid_args(msg);
1924
1925	if (app->role == HDP_SINK && config != HDP_NO_PREFERENCE_DC)
1926		return btd_error_invalid_args(msg);
1927
1928	if (app->role == HDP_SOURCE && config == HDP_NO_PREFERENCE_DC)
1929		return btd_error_invalid_args(msg);
1930
1931	if (!device->fr && config == HDP_STREAMING_DC)
1932		return btd_error_invalid_args(msg);
1933
1934	data = g_new0(struct hdp_create_dc, 1);
1935	data->dev = health_device_ref(device);
1936	data->config = config;
1937	data->app = hdp_application_ref(app);
1938	data->msg = dbus_message_ref(msg);
1939	data->conn = dbus_connection_ref(conn);
1940	data->cb = hdp_mdl_conn_cb;
1941
1942	if (hdp_get_mdep(device, l->data, device_get_mdep_cb,
1943						hdp_create_data_ref(data),
1944						destroy_create_dc_data, &err))
1945		return NULL;
1946
1947	reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1948							"%s", err->message);
1949	g_error_free(err);
1950	hdp_create_data_unref(data);
1951	return reply;
1952}
1953
1954static void hdp_mdl_delete_cb(GError *err, gpointer data)
1955{
1956	struct hdp_tmp_dc_data *del_data = data;
1957	DBusMessage *reply;
1958	char *path;
1959
1960	if (err && err->code != MCAP_INVALID_MDL) {
1961		reply = g_dbus_create_error(del_data->msg,
1962						ERROR_INTERFACE ".HealthError",
1963						"%s", err->message);
1964		g_dbus_send_message(del_data->conn, reply);
1965		return;
1966	}
1967
1968	path = g_strdup(del_data->hdp_chann->path);
1969	g_dbus_unregister_interface(del_data->conn, path, HEALTH_CHANNEL);
1970	g_free(path);
1971
1972	reply = g_dbus_create_reply(del_data->msg, DBUS_TYPE_INVALID);
1973	g_dbus_send_message(del_data->conn, reply);
1974}
1975
1976static void hdp_continue_del_cb(gpointer user_data, GError *err)
1977{
1978	struct hdp_tmp_dc_data *del_data = user_data;
1979	GError *gerr = NULL;
1980	DBusMessage *reply;
1981
1982	if (err) {
1983		reply = g_dbus_create_error(del_data->msg,
1984					ERROR_INTERFACE ".HealthError",
1985					"%s", err->message);
1986		g_dbus_send_message(del_data->conn, reply);
1987		return;
1988	}
1989
1990	if (mcap_delete_mdl(del_data->hdp_chann->mdl, hdp_mdl_delete_cb,
1991						hdp_tmp_dc_data_ref(del_data),
1992						hdp_tmp_dc_data_destroy, &gerr))
1993			return;
1994
1995	reply = g_dbus_create_error(del_data->msg,
1996						ERROR_INTERFACE ".HealthError",
1997						"%s", gerr->message);
1998	hdp_tmp_dc_data_unref(del_data);
1999	g_error_free(gerr);
2000	g_dbus_send_message(del_data->conn, reply);
2001}
2002
2003static DBusMessage *device_destroy_channel(DBusConnection *conn,
2004					DBusMessage *msg, void *user_data)
2005{
2006	struct hdp_device *device = user_data;
2007	struct hdp_tmp_dc_data *del_data;
2008	struct hdp_channel *hdp_chan;
2009	DBusMessage *reply;
2010	GError *err = NULL;
2011	char *path;
2012	GSList *l;
2013
2014	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
2015							DBUS_TYPE_INVALID)){
2016		return btd_error_invalid_args(msg);
2017	}
2018
2019	l = g_slist_find_custom(device->channels, path, cmp_chan_path);
2020	if (!l)
2021		return btd_error_invalid_args(msg);
2022
2023	hdp_chan = l->data;
2024	del_data = g_new0(struct hdp_tmp_dc_data, 1);
2025	del_data->msg = dbus_message_ref(msg);
2026	del_data->conn = dbus_connection_ref(conn);
2027	del_data->hdp_chann = hdp_channel_ref(hdp_chan);
2028
2029	if (device->mcl_conn) {
2030		if (mcap_delete_mdl(hdp_chan->mdl, hdp_mdl_delete_cb,
2031						hdp_tmp_dc_data_ref(del_data),
2032						hdp_tmp_dc_data_destroy, &err))
2033			return NULL;
2034		goto fail;
2035	}
2036
2037	if (hdp_establish_mcl(device, hdp_continue_del_cb,
2038						hdp_tmp_dc_data_ref(del_data),
2039						hdp_tmp_dc_data_destroy, &err))
2040		return NULL;
2041
2042fail:
2043	reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
2044							"%s", err->message);
2045	hdp_tmp_dc_data_unref(del_data);
2046	g_error_free(err);
2047	return reply;
2048}
2049
2050static DBusMessage *device_get_properties(DBusConnection *conn,
2051					DBusMessage *msg, void *user_data)
2052{
2053	struct hdp_device *device = user_data;
2054	DBusMessageIter iter, dict;
2055	DBusMessage *reply;
2056	char *path;
2057
2058	reply = dbus_message_new_method_return(msg);
2059	if (!reply)
2060		return NULL;
2061
2062	dbus_message_iter_init_append(reply, &iter);
2063
2064	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
2065			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
2066			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
2067			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
2068
2069	if (device->fr)
2070		path = g_strdup(device->fr->path);
2071	else
2072		path = g_strdup("");
2073	dict_append_entry(&dict, "MainChannel", DBUS_TYPE_OBJECT_PATH, &path);
2074	g_free(path);
2075	dbus_message_iter_close_container(&iter, &dict);
2076
2077	return reply;
2078}
2079
2080static void health_device_destroy(void *data)
2081{
2082	struct hdp_device *device = data;
2083
2084	DBG("Unregistered interface %s on path %s", HEALTH_DEVICE,
2085						device_get_path(device->dev));
2086
2087	remove_channels(device);
2088	if (device->ndc) {
2089		hdp_channel_unref(device->ndc);
2090		device->ndc = NULL;
2091	}
2092
2093	devices = g_slist_remove(devices, device);
2094	health_device_unref(device);
2095}
2096
2097static GDBusMethodTable health_device_methods[] = {
2098	{"Echo",		"",	"b",	device_echo,
2099						G_DBUS_METHOD_FLAG_ASYNC },
2100	{"CreateChannel",	"os",	"o",	device_create_channel,
2101						G_DBUS_METHOD_FLAG_ASYNC },
2102	{"DestroyChannel",	"o",	"",	device_destroy_channel,
2103						G_DBUS_METHOD_FLAG_ASYNC },
2104	{"GetProperties",	"",	"a{sv}", device_get_properties},
2105	{ NULL }
2106};
2107
2108static GDBusSignalTable health_device_signals[] = {
2109	{"ChannelConnected",		"o"		},
2110	{"ChannelDeleted",		"o"		},
2111	{"PropertyChanged",		"sv"		},
2112	{ NULL }
2113};
2114
2115static struct hdp_device *create_health_device(DBusConnection *conn,
2116						struct btd_device *device)
2117{
2118	struct btd_adapter *adapter = device_get_adapter(device);
2119	const gchar *path = device_get_path(device);
2120	struct hdp_device *dev;
2121	GSList *l;
2122
2123	if (!device)
2124		return NULL;
2125
2126	dev = g_new0(struct hdp_device, 1);
2127	dev->conn = dbus_connection_ref(conn);
2128	dev->dev = btd_device_ref(device);
2129	health_device_ref(dev);
2130
2131	l = g_slist_find_custom(adapters, adapter, cmp_adapter);
2132	if (!l)
2133		goto fail;
2134
2135	dev->hdp_adapter = l->data;
2136
2137	if (!g_dbus_register_interface(conn, path,
2138					HEALTH_DEVICE,
2139					health_device_methods,
2140					health_device_signals, NULL,
2141					dev, health_device_destroy)) {
2142		error("D-Bus failed to register %s interface", HEALTH_DEVICE);
2143		goto fail;
2144	}
2145
2146	DBG("Registered interface %s on path %s", HEALTH_DEVICE, path);
2147	return dev;
2148
2149fail:
2150	health_device_unref(dev);
2151	return NULL;
2152}
2153
2154int hdp_device_register(DBusConnection *conn, struct btd_device *device)
2155{
2156	struct hdp_device *hdev;
2157	GSList *l;
2158
2159	l = g_slist_find_custom(devices, device, cmp_device);
2160	if (l) {
2161		hdev = l->data;
2162		hdev->sdp_present = TRUE;
2163		return 0;
2164	}
2165
2166	hdev = create_health_device(conn, device);
2167	if (!hdev)
2168		return -1;
2169
2170	hdev->sdp_present = TRUE;
2171
2172	devices = g_slist_prepend(devices, hdev);
2173	return 0;
2174}
2175
2176void hdp_device_unregister(struct btd_device *device)
2177{
2178	struct hdp_device *hdp_dev;
2179	const char *path;
2180	GSList *l;
2181
2182	l = g_slist_find_custom(devices, device, cmp_device);
2183	if (!l)
2184		return;
2185
2186	hdp_dev = l->data;
2187	path = device_get_path(hdp_dev->dev);
2188	g_dbus_unregister_interface(hdp_dev->conn, path, HEALTH_DEVICE);
2189}
2190
2191int hdp_manager_start(DBusConnection *conn)
2192{
2193	DBG("Starting Health manager");
2194
2195	if (!g_dbus_register_interface(conn, MANAGER_PATH,
2196					HEALTH_MANAGER,
2197					health_manager_methods, NULL, NULL,
2198					NULL, manager_path_unregister)) {
2199		error("D-Bus failed to register %s interface", HEALTH_MANAGER);
2200		return -1;
2201	}
2202
2203	connection = dbus_connection_ref(conn);
2204
2205	return 0;
2206}
2207
2208void hdp_manager_stop(void)
2209{
2210	g_dbus_unregister_interface(connection, MANAGER_PATH, HEALTH_MANAGER);
2211
2212	dbus_connection_unref(connection);
2213	DBG("Stopped Health manager");
2214}
2215
2216struct hdp_device *health_device_ref(struct hdp_device *hdp_dev)
2217{
2218	hdp_dev->ref++;
2219
2220	DBG("health_device_ref(%p): ref=%d", hdp_dev, hdp_dev->ref);
2221
2222	return hdp_dev;
2223}
2224
2225void health_device_unref(struct hdp_device *hdp_dev)
2226{
2227	hdp_dev->ref--;
2228
2229	DBG("health_device_unref(%p): ref=%d", hdp_dev, hdp_dev->ref);
2230
2231	if (hdp_dev->ref > 0)
2232		return;
2233
2234	free_health_device(hdp_dev);
2235}
2236