Home | History | Annotate | Download | only in health
      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 
     52 static DBusConnection *connection = NULL;
     53 
     54 static GSList *applications = NULL;
     55 static GSList *devices = NULL;
     56 static uint8_t next_app_id = HDP_MDEP_INITIAL;
     57 
     58 static GSList *adapters;
     59 
     60 static gboolean update_adapter(struct hdp_adapter *adapter);
     61 static struct hdp_device *create_health_device(DBusConnection *conn,
     62 						struct btd_device *device);
     63 static void free_echo_data(struct hdp_echo_data *edata);
     64 
     65 struct 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 
     76 struct 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 
     84 struct 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 
     90 static 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 
    101 static 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 
    115 static 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 
    129 static 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 
    139 static 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 
    148 static 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 
    160 static 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 
    169 static 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 
    178 static 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 
    190 static 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 
    198 static 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 
    209 static 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 
    220 static 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 
    229 static 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 
    238 static 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 
    246 static 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 
    254 static 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 
    263 static 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 
    281 static 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 
    288 static 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 
    298 static 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 
    309 static 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 
    326 static 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 
    334 static 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 
    345 static 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 
    390 static 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 
    417 static 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 
    427 static GDBusMethodTable health_manager_methods[] = {
    428 	{"CreateApplication", "a{sv}", "o", manager_create_application},
    429 	{"DestroyApplication", "o", "", manager_destroy_application},
    430 	{ NULL }
    431 };
    432 
    433 static 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 
    473 static 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 
    480 static void abort_mdl_cb(GError *err, gpointer data)
    481 {
    482 	if (err)
    483 		error("Aborting error: %s", err->message);
    484 }
    485 
    486 static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
    487 {
    488 	struct hdp_tmp_dc_data *dc_data = data;
    489 	DBusMessage *reply;
    490 	int fd;
    491 
    492 	if (err) {
    493 		struct hdp_channel *chan = dc_data->hdp_chann;
    494 		GError *gerr = NULL;
    495 
    496 		error("%s", err->message);
    497 		reply = g_dbus_create_error(dc_data->msg,
    498 					ERROR_INTERFACE ".HealthError",
    499 					"Cannot reconnect: %s", err->message);
    500 		g_dbus_send_message(dc_data->conn, reply);
    501 
    502 		/* Send abort request because remote side */
    503 		/* is now in PENDING state */
    504 		if (!mcap_mdl_abort(chan->mdl, abort_mdl_cb, NULL, NULL,
    505 								&gerr)) {
    506 			error("%s", gerr->message);
    507 			g_error_free(gerr);
    508 		}
    509 		return;
    510 	}
    511 
    512 	fd = mcap_mdl_get_fd(dc_data->hdp_chann->mdl);
    513 	if (fd < 0) {
    514 		reply = g_dbus_create_error(dc_data->msg,
    515 						ERROR_INTERFACE ".HealthError",
    516 						"Cannot get file descriptor");
    517 		g_dbus_send_message(dc_data->conn, reply);
    518 		return;
    519 	}
    520 
    521 	reply = g_dbus_create_reply(dc_data->msg, DBUS_TYPE_UNIX_FD,
    522 							&fd, DBUS_TYPE_INVALID);
    523 	g_dbus_send_message(dc_data->conn, reply);
    524 
    525 	g_dbus_emit_signal(dc_data->conn,
    526 			device_get_path(dc_data->hdp_chann->dev->dev),
    527 			HEALTH_DEVICE, "ChannelConnected",
    528 			DBUS_TYPE_OBJECT_PATH, &dc_data->hdp_chann->path,
    529 			DBUS_TYPE_INVALID);
    530 }
    531 
    532 static void hdp_get_dcpsm_cb(uint16_t dcpsm, gpointer user_data, GError *err)
    533 {
    534 	struct hdp_tmp_dc_data *hdp_conn = user_data;
    535 	struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
    536 	GError *gerr = NULL;
    537 	uint8_t mode;
    538 
    539 	if (err) {
    540 		hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
    541 		return;
    542 	}
    543 
    544 	if (hdp_chann->config == HDP_RELIABLE_DC)
    545 		mode = L2CAP_MODE_ERTM;
    546 	else
    547 		mode = L2CAP_MODE_STREAMING;
    548 
    549 	if (mcap_connect_mdl(hdp_chann->mdl, mode, dcpsm, hdp_conn->cb,
    550 					hdp_tmp_dc_data_ref(hdp_conn),
    551 					hdp_tmp_dc_data_destroy, &gerr))
    552 		return;
    553 
    554 	hdp_tmp_dc_data_unref(hdp_conn);
    555 	hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
    556 	g_error_free(gerr);
    557 	gerr = NULL;
    558 }
    559 
    560 static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
    561 								gpointer data)
    562 {
    563 	struct hdp_tmp_dc_data *dc_data = data;
    564 	GError *gerr = NULL;
    565 	DBusMessage *reply;
    566 
    567 	if (err) {
    568 		reply = g_dbus_create_error(dc_data->msg,
    569 					ERROR_INTERFACE ".HealthError",
    570 					"Cannot reconnect: %s", err->message);
    571 		g_dbus_send_message(dc_data->conn, reply);
    572 		return;
    573 	}
    574 
    575 	dc_data->cb = hdp_mdl_reconn_cb;
    576 
    577 	if (hdp_get_dcpsm(dc_data->hdp_chann->dev, hdp_get_dcpsm_cb,
    578 					hdp_tmp_dc_data_ref(dc_data),
    579 					hdp_tmp_dc_data_destroy, &gerr))
    580 		return;
    581 
    582 	error("%s", gerr->message);
    583 
    584 	reply = g_dbus_create_error(dc_data->msg,
    585 					ERROR_INTERFACE ".HealthError",
    586 					"Cannot reconnect: %s", gerr->message);
    587 	g_dbus_send_message(dc_data->conn, reply);
    588 	hdp_tmp_dc_data_unref(dc_data);
    589 	g_error_free(gerr);
    590 
    591 	/* Send abort request because remote side is now in PENDING state */
    592 	if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) {
    593 		error("%s", gerr->message);
    594 		g_error_free(gerr);
    595 	}
    596 }
    597 
    598 static DBusMessage *channel_acquire_continue(struct hdp_tmp_dc_data *data,
    599 								GError *err)
    600 {
    601 	DBusMessage *reply;
    602 	GError *gerr = NULL;
    603 	int fd;
    604 
    605 	if (err) {
    606 		return g_dbus_create_error(data->msg,
    607 						ERROR_INTERFACE ".HealthError",
    608 						"%s", err->message);
    609 	}
    610 
    611 	fd = mcap_mdl_get_fd(data->hdp_chann->mdl);
    612 	if (fd >= 0)
    613 		return g_dbus_create_reply(data->msg, DBUS_TYPE_UNIX_FD, &fd,
    614 							DBUS_TYPE_INVALID);
    615 
    616 	hdp_tmp_dc_data_ref(data);
    617 	if (mcap_reconnect_mdl(data->hdp_chann->mdl, device_reconnect_mdl_cb,
    618 					data, hdp_tmp_dc_data_destroy, &gerr))
    619 		return NULL;
    620 
    621 	hdp_tmp_dc_data_unref(data);
    622 	reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
    623 					"Cannot reconnect: %s", gerr->message);
    624 	g_error_free(gerr);
    625 
    626 	return reply;
    627 }
    628 
    629 static void channel_acquire_cb(gpointer data, GError *err)
    630 {
    631 	struct hdp_tmp_dc_data *dc_data = data;
    632 	DBusMessage *reply;
    633 
    634 	reply = channel_acquire_continue(data, err);
    635 
    636 	if (reply)
    637 		g_dbus_send_message(dc_data->conn, reply);
    638 }
    639 
    640 static DBusMessage *channel_acquire(DBusConnection *conn,
    641 					DBusMessage *msg, void *user_data)
    642 {
    643 	struct hdp_channel *chan = user_data;
    644 	struct hdp_tmp_dc_data *dc_data;
    645 	GError *gerr = NULL;
    646 	DBusMessage *reply;
    647 
    648 	dc_data = g_new0(struct hdp_tmp_dc_data, 1);
    649 	dc_data->conn = dbus_connection_ref(conn);
    650 	dc_data->msg = dbus_message_ref(msg);
    651 	dc_data->hdp_chann = hdp_channel_ref(chan);
    652 
    653 	if (chan->dev->mcl_conn) {
    654 		reply = channel_acquire_continue(hdp_tmp_dc_data_ref(dc_data),
    655 									NULL);
    656 		hdp_tmp_dc_data_unref(dc_data);
    657 		return reply;
    658 	}
    659 
    660 	if (hdp_establish_mcl(chan->dev, channel_acquire_cb,
    661 						hdp_tmp_dc_data_ref(dc_data),
    662 						hdp_tmp_dc_data_destroy, &gerr))
    663 		return NULL;
    664 
    665 	reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
    666 					"%s", gerr->message);
    667 	hdp_tmp_dc_data_unref(dc_data);
    668 	g_error_free(gerr);
    669 
    670 	return reply;
    671 }
    672 
    673 static void close_mdl(struct hdp_channel *hdp_chann)
    674 {
    675 	int fd;
    676 
    677 	fd = mcap_mdl_get_fd(hdp_chann->mdl);
    678 	if (fd < 0)
    679 		return;
    680 
    681 	close(fd);
    682 }
    683 
    684 static DBusMessage *channel_release(DBusConnection *conn,
    685 					DBusMessage *msg, void *user_data)
    686 {
    687 	struct hdp_channel *hdp_chann = user_data;
    688 
    689 	close_mdl(hdp_chann);
    690 
    691 	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
    692 }
    693 
    694 static void free_echo_data(struct hdp_echo_data *edata)
    695 {
    696 	if (!edata)
    697 		return;
    698 
    699 	if (edata->tid)
    700 		g_source_remove(edata->tid);
    701 
    702 	if (edata->buf)
    703 		g_free(edata->buf);
    704 
    705 
    706 	g_free(edata);
    707 }
    708 
    709 static void health_channel_destroy(void *data)
    710 {
    711 	struct hdp_channel *hdp_chan = data;
    712 	struct hdp_device *dev = hdp_chan->dev;
    713 
    714 	DBG("Destroy Health Channel %s", hdp_chan->path);
    715 	if (!g_slist_find(dev->channels, hdp_chan))
    716 		goto end;
    717 
    718 	dev->channels = g_slist_remove(dev->channels, hdp_chan);
    719 
    720 	if (hdp_chan->mdep != HDP_MDEP_ECHO)
    721 		g_dbus_emit_signal(dev->conn, device_get_path(dev->dev),
    722 					HEALTH_DEVICE, "ChannelDeleted",
    723 					DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
    724 					DBUS_TYPE_INVALID);
    725 
    726 	if (hdp_chan == dev->fr) {
    727 		char *empty_path;
    728 
    729 		hdp_channel_unref(dev->fr);
    730 		dev->fr = NULL;
    731 		empty_path = "/";
    732 		emit_property_changed(dev->conn, device_get_path(dev->dev),
    733 					HEALTH_DEVICE, "MainChannel",
    734 					DBUS_TYPE_OBJECT_PATH, &empty_path);
    735 	}
    736 
    737 end:
    738 	hdp_channel_unref(hdp_chan);
    739 }
    740 
    741 static GDBusMethodTable health_channels_methods[] = {
    742 	{"GetProperties","",	"a{sv}",	channel_get_properties },
    743 	{"Acquire",	"",	"h",		channel_acquire,
    744 						G_DBUS_METHOD_FLAG_ASYNC },
    745 	{"Release",	"",	"",		channel_release },
    746 	{ NULL }
    747 };
    748 
    749 static struct hdp_channel *create_channel(struct hdp_device *dev,
    750 						uint8_t config,
    751 						struct mcap_mdl *mdl,
    752 						uint16_t mdlid,
    753 						struct hdp_application *app,
    754 						GError **err)
    755 {
    756 	struct hdp_channel *hdp_chann;
    757 
    758 	if (!dev)
    759 		return NULL;
    760 
    761 	hdp_chann = g_new0(struct hdp_channel, 1);
    762 	hdp_chann->config = config;
    763 	hdp_chann->dev = health_device_ref(dev);
    764 	hdp_chann->mdlid = mdlid;
    765 
    766 	if (mdl)
    767 		hdp_chann->mdl = mcap_mdl_ref(mdl);
    768 
    769 	if (app) {
    770 		hdp_chann->mdep = app->id;
    771 		hdp_chann->app = hdp_application_ref(app);
    772 	} else
    773 		hdp_chann->edata = g_new0(struct hdp_echo_data, 1);
    774 
    775 	hdp_chann->path = g_strdup_printf("%s/chan%d",
    776 					device_get_path(hdp_chann->dev->dev),
    777 					hdp_chann->mdlid);
    778 
    779 	dev->channels = g_slist_append(dev->channels,
    780 						hdp_channel_ref(hdp_chann));
    781 
    782 	if (hdp_chann->mdep == HDP_MDEP_ECHO)
    783 		return hdp_channel_ref(hdp_chann);
    784 
    785 	if (!g_dbus_register_interface(dev->conn, hdp_chann->path,
    786 					HEALTH_CHANNEL,
    787 					health_channels_methods, NULL, NULL,
    788 					hdp_chann, health_channel_destroy)) {
    789 		g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
    790 					"Can't register the channel interface");
    791 		health_channel_destroy(hdp_chann);
    792 		return NULL;
    793 	}
    794 
    795 	return hdp_channel_ref(hdp_chann);
    796 }
    797 
    798 static void remove_channels(struct hdp_device *dev)
    799 {
    800 	struct hdp_channel *chan;
    801 	char *path;
    802 
    803 	while (dev->channels) {
    804 		chan = dev->channels->data;
    805 
    806 		path = g_strdup(chan->path);
    807 		if (!g_dbus_unregister_interface(dev->conn, path,
    808 								HEALTH_CHANNEL))
    809 			health_channel_destroy(chan);
    810 		g_free(path);
    811 	}
    812 }
    813 
    814 static void close_device_con(struct hdp_device *dev, gboolean cache)
    815 {
    816 	if (!dev->mcl)
    817 		return;
    818 
    819 	mcap_close_mcl(dev->mcl, cache);
    820 	dev->mcl_conn = FALSE;
    821 
    822 	if (cache)
    823 		return;
    824 
    825 	device_unref_mcl(dev);
    826 	remove_channels(dev);
    827 
    828 	if (!dev->sdp_present) {
    829 		const char *path;
    830 
    831 		path = device_get_path(dev->dev);
    832 		g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE);
    833 	}
    834 }
    835 
    836 static int send_echo_data(int sock, const void *buf, uint32_t size)
    837 {
    838 	const uint8_t *buf_b = buf;
    839 	uint32_t sent = 0;
    840 
    841 	while (sent < size) {
    842 		int n = write(sock, buf_b + sent, size - sent);
    843 		if (n < 0)
    844 			return -1;
    845 		sent += n;
    846 	}
    847 
    848 	return 0;
    849 }
    850 
    851 static gboolean serve_echo(GIOChannel *io_chan, GIOCondition cond,
    852 								gpointer data)
    853 {
    854 	struct hdp_channel *chan = data;
    855 	uint8_t buf[MCAP_DC_MTU];
    856 	int fd, len;
    857 
    858 	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
    859 		hdp_channel_unref(chan);
    860 		return FALSE;
    861 	}
    862 
    863 	if (chan->edata->echo_done)
    864 		goto fail;
    865 
    866 	chan->edata->echo_done = TRUE;
    867 
    868 	fd = g_io_channel_unix_get_fd(io_chan);
    869 	len = read(fd, buf, sizeof(buf));
    870 
    871 	if (send_echo_data(fd, buf, len)  >= 0)
    872 		return TRUE;
    873 
    874 fail:
    875 	close_device_con(chan->dev, FALSE);
    876 	hdp_channel_unref(chan);
    877 	return FALSE;
    878 }
    879 
    880 static gboolean check_channel_conf(struct hdp_channel *chan)
    881 {
    882 	GError *err = NULL;
    883 	GIOChannel *io;
    884 	uint8_t mode;
    885 	uint16_t imtu, omtu;
    886 	int fd;
    887 
    888 	fd = mcap_mdl_get_fd(chan->mdl);
    889 	if (fd < 0)
    890 		return FALSE;
    891 	io = g_io_channel_unix_new(fd);
    892 
    893 	if (!bt_io_get(io, BT_IO_L2CAP, &err,
    894 			BT_IO_OPT_MODE, &mode,
    895 			BT_IO_OPT_IMTU, &imtu,
    896 			BT_IO_OPT_OMTU, &omtu,
    897 			BT_IO_OPT_INVALID)) {
    898 		error("Error: %s", err->message);
    899 		g_io_channel_unref(io);
    900 		g_error_free(err);
    901 		return FALSE;
    902 	}
    903 
    904 	g_io_channel_unref(io);
    905 
    906 	switch (chan->config) {
    907 	case HDP_RELIABLE_DC:
    908 		if (mode != L2CAP_MODE_ERTM)
    909 			return FALSE;
    910 		break;
    911 	case HDP_STREAMING_DC:
    912 		if (mode != L2CAP_MODE_STREAMING)
    913 			return FALSE;
    914 		break;
    915 	default:
    916 		error("Error: Connected with unknown configuration");
    917 		return FALSE;
    918 	}
    919 
    920 	DBG("MDL imtu %d omtu %d Channel imtu %d omtu %d", imtu, omtu,
    921 						chan->imtu, chan->omtu);
    922 
    923 	if (!chan->imtu)
    924 		chan->imtu = imtu;
    925 	if (!chan->omtu)
    926 		chan->omtu = omtu;
    927 
    928 	if (chan->imtu != imtu || chan->omtu != omtu)
    929 		return FALSE;
    930 
    931 	return TRUE;
    932 }
    933 
    934 static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
    935 {
    936 	struct hdp_device *dev = data;
    937 	struct hdp_channel *chan;
    938 
    939 	DBG("hdp_mcap_mdl_connected_cb");
    940 	if (!dev->ndc)
    941 		return;
    942 
    943 	chan = dev->ndc;
    944 	if (!chan->mdl)
    945 		chan->mdl = mcap_mdl_ref(mdl);
    946 
    947 	if (!g_slist_find(dev->channels, chan))
    948 		dev->channels = g_slist_prepend(dev->channels,
    949 							hdp_channel_ref(chan));
    950 
    951 	if (!check_channel_conf(chan)) {
    952 		close_mdl(chan);
    953 		goto end;
    954 	}
    955 
    956 	if (chan->mdep == HDP_MDEP_ECHO) {
    957 		GIOChannel *io;
    958 		int fd;
    959 
    960 		fd = mcap_mdl_get_fd(chan->mdl);
    961 		if (fd < 0)
    962 			goto end;
    963 
    964 		chan->edata->echo_done = FALSE;
    965 		io = g_io_channel_unix_new(fd);
    966 		g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
    967 				serve_echo, hdp_channel_ref(chan));
    968 		g_io_channel_unref(io);
    969 		goto end;
    970 	}
    971 
    972 	g_dbus_emit_signal(dev->conn, device_get_path(dev->dev), HEALTH_DEVICE,
    973 					"ChannelConnected",
    974 					DBUS_TYPE_OBJECT_PATH, &chan->path,
    975 					DBUS_TYPE_INVALID);
    976 
    977 	if (dev->fr)
    978 		goto end;
    979 
    980 	dev->fr = hdp_channel_ref(chan);
    981 
    982 	emit_property_changed(dev->conn, device_get_path(dev->dev),
    983 					HEALTH_DEVICE, "MainChannel",
    984 					DBUS_TYPE_OBJECT_PATH, &dev->fr->path);
    985 
    986 end:
    987 	hdp_channel_unref(dev->ndc);
    988 	dev->ndc = NULL;
    989 }
    990 
    991 static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
    992 {
    993 	/* struct hdp_device *dev = data; */
    994 
    995 	DBG("hdp_mcap_mdl_closed_cb");
    996 
    997 	/* Nothing to do */
    998 }
    999 
   1000 static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
   1001 {
   1002 	struct hdp_device *dev = data;
   1003 	struct hdp_channel *chan;
   1004 	char *path;
   1005 	GSList *l;
   1006 
   1007 	DBG("hdp_mcap_mdl_deleted_cb");
   1008 	l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
   1009 	if (!l)
   1010 		return;
   1011 
   1012 	chan = l->data;
   1013 
   1014 	path = g_strdup(chan->path);
   1015 	if (!g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL))
   1016 		health_channel_destroy(chan);
   1017 	g_free(path);
   1018 }
   1019 
   1020 static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
   1021 {
   1022 	struct hdp_device *dev = data;
   1023 
   1024 	DBG("hdp_mcap_mdl_aborted_cb");
   1025 	if (!dev->ndc)
   1026 		return;
   1027 
   1028 	dev->ndc->mdl = mcap_mdl_ref(mdl);
   1029 
   1030 	if (!g_slist_find(dev->channels, dev->ndc))
   1031 		dev->channels = g_slist_prepend(dev->channels,
   1032 						hdp_channel_ref(dev->ndc));
   1033 
   1034 	if (dev->ndc->mdep != HDP_MDEP_ECHO)
   1035 		g_dbus_emit_signal(dev->conn, device_get_path(dev->dev),
   1036 					HEALTH_DEVICE, "ChannelConnected",
   1037 					DBUS_TYPE_OBJECT_PATH, &dev->ndc->path,
   1038 					DBUS_TYPE_INVALID);
   1039 
   1040 	hdp_channel_unref(dev->ndc);
   1041 	dev->ndc = NULL;
   1042 }
   1043 
   1044 static uint8_t hdp2l2cap_mode(uint8_t hdp_mode)
   1045 {
   1046 	return hdp_mode == HDP_STREAMING_DC ? L2CAP_MODE_STREAMING :
   1047 								L2CAP_MODE_ERTM;
   1048 }
   1049 
   1050 static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
   1051 				uint16_t mdlid, uint8_t *conf, void *data)
   1052 {
   1053 	struct hdp_device *dev = data;
   1054 	struct hdp_application *app;
   1055 	GError *err = NULL;
   1056 	GSList *l;
   1057 
   1058 	DBG("Data channel request");
   1059 
   1060 	if (mdepid == HDP_MDEP_ECHO) {
   1061 		switch (*conf) {
   1062 		case HDP_NO_PREFERENCE_DC:
   1063 			*conf = HDP_RELIABLE_DC;
   1064 		case HDP_RELIABLE_DC:
   1065 			break;
   1066 		case HDP_STREAMING_DC:
   1067 			return MCAP_CONFIGURATION_REJECTED;
   1068 		default:
   1069 			/* Special case defined in HDP spec 3.4. When an invalid
   1070 			* configuration is received we shall close the MCL when
   1071 			* we are still processing the callback. */
   1072 			close_device_con(dev, FALSE);
   1073 			return MCAP_CONFIGURATION_REJECTED; /* not processed */
   1074 		}
   1075 
   1076 		if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
   1077 						L2CAP_MODE_ERTM, &err)) {
   1078 			error("Error: %s", err->message);
   1079 			g_error_free(err);
   1080 			return MCAP_MDL_BUSY;
   1081 		}
   1082 
   1083 		dev->ndc = create_channel(dev, *conf, NULL, mdlid, NULL, NULL);
   1084 		if (!dev->ndc)
   1085 			return MCAP_MDL_BUSY;
   1086 
   1087 		return MCAP_SUCCESS;
   1088 	}
   1089 
   1090 	l = g_slist_find_custom(applications, &mdepid, cmp_app_id);
   1091 	if (!l)
   1092 		return MCAP_INVALID_MDEP;
   1093 
   1094 	app = l->data;
   1095 
   1096 	/* Check if is the first dc if so,
   1097 	* only reliable configuration is allowed */
   1098 	switch (*conf) {
   1099 	case HDP_NO_PREFERENCE_DC:
   1100 		if (app->role == HDP_SINK)
   1101 			return MCAP_CONFIGURATION_REJECTED;
   1102 		else if (dev->fr && app->chan_type_set)
   1103 			*conf = app->chan_type;
   1104 		else
   1105 			*conf = HDP_RELIABLE_DC;
   1106 		break;
   1107 	case HDP_STREAMING_DC:
   1108 		if (!dev->fr || app->role == HDP_SOURCE)
   1109 			return MCAP_CONFIGURATION_REJECTED;
   1110 	case HDP_RELIABLE_DC:
   1111 		if (app->role == HDP_SOURCE)
   1112 			return MCAP_CONFIGURATION_REJECTED;
   1113 		break;
   1114 	default:
   1115 		/* Special case defined in HDP spec 3.4. When an invalid
   1116 		* configuration is received we shall close the MCL when
   1117 		* we are still processing the callback. */
   1118 		close_device_con(dev, FALSE);
   1119 		return MCAP_CONFIGURATION_REJECTED; /* not processed */
   1120 	}
   1121 
   1122 	l = g_slist_find_custom(dev->channels, &mdlid, cmp_chan_mdlid);
   1123 	if (l) {
   1124 		struct hdp_channel *chan = l->data;
   1125 		char *path;
   1126 
   1127 		path = g_strdup(chan->path);
   1128 		g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL);
   1129 		g_free(path);
   1130 	}
   1131 
   1132 	if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
   1133 						hdp2l2cap_mode(*conf), &err)) {
   1134 		error("Error: %s", err->message);
   1135 		g_error_free(err);
   1136 		return MCAP_MDL_BUSY;
   1137 	}
   1138 
   1139 	dev->ndc = create_channel(dev, *conf, NULL, mdlid, app, NULL);
   1140 	if (!dev->ndc)
   1141 		return MCAP_MDL_BUSY;
   1142 
   1143 	return MCAP_SUCCESS;
   1144 }
   1145 
   1146 static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
   1147 {
   1148 	struct hdp_device *dev = data;
   1149 	struct hdp_channel *chan;
   1150 	GError *err = NULL;
   1151 	GSList *l;
   1152 
   1153 	l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
   1154 	if (!l)
   1155 		return MCAP_INVALID_MDL;
   1156 
   1157 	chan = l->data;
   1158 
   1159 	if (!dev->fr && (chan->config != HDP_RELIABLE_DC) &&
   1160 						(chan->mdep != HDP_MDEP_ECHO))
   1161 		return MCAP_UNSPECIFIED_ERROR;
   1162 
   1163 	if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
   1164 					hdp2l2cap_mode(chan->config), &err)) {
   1165 		error("Error: %s", err->message);
   1166 		g_error_free(err);
   1167 		return MCAP_MDL_BUSY;
   1168 	}
   1169 
   1170 	dev->ndc = hdp_channel_ref(chan);
   1171 
   1172 	return MCAP_SUCCESS;
   1173 }
   1174 
   1175 gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err)
   1176 {
   1177 	gboolean ret;
   1178 
   1179 	if (!device->mcl)
   1180 		return FALSE;
   1181 
   1182 	ret = mcap_mcl_set_cb(device->mcl, device, err,
   1183 		MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
   1184 		MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
   1185 		MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
   1186 		MCAP_MDL_CB_ABORTED, hdp_mcap_mdl_aborted_cb,
   1187 		MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
   1188 		MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
   1189 		MCAP_MDL_CB_INVALID);
   1190 
   1191 	if (ret)
   1192 		return TRUE;
   1193 
   1194 	error("Can't set mcl callbacks, closing mcl");
   1195 	close_device_con(device, TRUE);
   1196 
   1197 	return FALSE;
   1198 }
   1199 
   1200 static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
   1201 {
   1202 	struct hdp_device *hdp_device;
   1203 	bdaddr_t addr;
   1204 	GSList *l;
   1205 
   1206 	mcap_mcl_get_addr(mcl, &addr);
   1207 	l = g_slist_find_custom(devices, &addr, cmp_dev_addr);
   1208 	if (!l) {
   1209 		struct hdp_adapter *hdp_adapter = data;
   1210 		struct btd_device *device;
   1211 		char str[18];
   1212 
   1213 		ba2str(&addr, str);
   1214 		device = adapter_get_device(connection,
   1215 					hdp_adapter->btd_adapter, str);
   1216 		if (!device)
   1217 			return;
   1218 		hdp_device = create_health_device(connection, device);
   1219 		if (!hdp_device)
   1220 			return;
   1221 		devices = g_slist_append(devices, hdp_device);
   1222 	} else
   1223 		hdp_device = l->data;
   1224 
   1225 	hdp_device->mcl = mcap_mcl_ref(mcl);
   1226 	hdp_device->mcl_conn = TRUE;
   1227 
   1228 	DBG("New mcl connected from  %s", device_get_path(hdp_device->dev));
   1229 
   1230 	hdp_set_mcl_cb(hdp_device, NULL);
   1231 }
   1232 
   1233 static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
   1234 {
   1235 	struct hdp_device *hdp_device;
   1236 	GSList *l;
   1237 
   1238 	l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
   1239 	if (!l)
   1240 		return;
   1241 
   1242 	hdp_device = l->data;
   1243 	hdp_device->mcl_conn = TRUE;
   1244 
   1245 	DBG("MCL reconnected %s", device_get_path(hdp_device->dev));
   1246 
   1247 	hdp_set_mcl_cb(hdp_device, NULL);
   1248 }
   1249 
   1250 static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
   1251 {
   1252 	struct hdp_device *hdp_device;
   1253 	GSList *l;
   1254 
   1255 	l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
   1256 	if (!l)
   1257 		return;
   1258 
   1259 	hdp_device = l->data;
   1260 	hdp_device->mcl_conn = FALSE;
   1261 
   1262 	DBG("Mcl disconnected %s", device_get_path(hdp_device->dev));
   1263 }
   1264 
   1265 static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
   1266 {
   1267 	struct hdp_device *hdp_device;
   1268 	const char *path;
   1269 	GSList *l;
   1270 
   1271 	l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
   1272 	if (!l)
   1273 		return;
   1274 
   1275 	hdp_device = l->data;
   1276 	device_unref_mcl(hdp_device);
   1277 
   1278 	if (hdp_device->sdp_present)
   1279 		return;
   1280 
   1281 	/* Because remote device hasn't announced an HDP record */
   1282 	/* the Bluetooth daemon won't notify when the device shall */
   1283 	/* be removed. Then we have to remove the HealthDevice */
   1284 	/* interface manually */
   1285 	path = device_get_path(hdp_device->dev);
   1286 	g_dbus_unregister_interface(hdp_device->conn, path, HEALTH_DEVICE);
   1287 	DBG("Mcl uncached %s", path);
   1288 }
   1289 
   1290 static void check_devices_mcl(void)
   1291 {
   1292 	struct hdp_device *dev;
   1293 	GSList *l, *to_delete = NULL;
   1294 
   1295 	for (l = devices; l; l = l->next) {
   1296 		dev = l->data;
   1297 		device_unref_mcl(dev);
   1298 
   1299 		if (!dev->sdp_present)
   1300 			to_delete = g_slist_append(to_delete, dev);
   1301 		else
   1302 			remove_channels(dev);
   1303 	}
   1304 
   1305 	for (l = to_delete; l; l = l->next) {
   1306 		const char *path;
   1307 
   1308 		path = device_get_path(dev->dev);
   1309 		g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE);
   1310 	}
   1311 
   1312 	g_slist_free(to_delete);
   1313 }
   1314 
   1315 static void release_adapter_instance(struct hdp_adapter *hdp_adapter)
   1316 {
   1317 	if (!hdp_adapter->mi)
   1318 		return;
   1319 
   1320 	check_devices_mcl();
   1321 	mcap_release_instance(hdp_adapter->mi);
   1322 	mcap_instance_unref(hdp_adapter->mi);
   1323 	hdp_adapter->mi = NULL;
   1324 }
   1325 
   1326 static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
   1327 {
   1328 	GError *err = NULL;
   1329 	bdaddr_t addr;
   1330 
   1331 	if (!applications) {
   1332 		release_adapter_instance(hdp_adapter);
   1333 		goto update;
   1334 	}
   1335 
   1336 	if (hdp_adapter->mi)
   1337 		goto update;
   1338 
   1339 	adapter_get_address(hdp_adapter->btd_adapter, &addr);
   1340 	hdp_adapter->mi = mcap_create_instance(&addr, BT_IO_SEC_MEDIUM, 0, 0,
   1341 					mcl_connected, mcl_reconnected,
   1342 					mcl_disconnected, mcl_uncached,
   1343 					NULL, /* CSP is not used by now */
   1344 					hdp_adapter, &err);
   1345 
   1346 	if (!hdp_adapter->mi) {
   1347 		error("Error creating the MCAP instance: %s", err->message);
   1348 		g_error_free(err);
   1349 		return FALSE;
   1350 	}
   1351 
   1352 	hdp_adapter->ccpsm = mcap_get_ctrl_psm(hdp_adapter->mi, &err);
   1353 	if (err) {
   1354 		error("Error getting MCAP control PSM: %s", err->message);
   1355 		goto fail;
   1356 	}
   1357 
   1358 	hdp_adapter->dcpsm = mcap_get_data_psm(hdp_adapter->mi, &err);
   1359 	if (err) {
   1360 		error("Error getting MCAP data PSM: %s", err->message);
   1361 		goto fail;
   1362 	}
   1363 
   1364 update:
   1365 	if (hdp_update_sdp_record(hdp_adapter, applications))
   1366 		return TRUE;
   1367 	error("Error updating the SDP record");
   1368 
   1369 fail:
   1370 	release_adapter_instance(hdp_adapter);
   1371 	if (err)
   1372 		g_error_free(err);
   1373 	return FALSE;
   1374 }
   1375 
   1376 int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *adapter)
   1377 {
   1378 	struct hdp_adapter *hdp_adapter;
   1379 
   1380 	hdp_adapter = g_new0(struct hdp_adapter, 1);
   1381 	hdp_adapter->btd_adapter = btd_adapter_ref(adapter);
   1382 
   1383 	if(!update_adapter(hdp_adapter))
   1384 		goto fail;
   1385 
   1386 	adapters = g_slist_append(adapters, hdp_adapter);
   1387 
   1388 	return 0;
   1389 
   1390 fail:
   1391 	btd_adapter_unref(hdp_adapter->btd_adapter);
   1392 	g_free(hdp_adapter);
   1393 	return -1;
   1394 }
   1395 
   1396 void hdp_adapter_unregister(struct btd_adapter *adapter)
   1397 {
   1398 	struct hdp_adapter *hdp_adapter;
   1399 	GSList *l;
   1400 
   1401 	l = g_slist_find_custom(adapters, adapter, cmp_adapter);
   1402 
   1403 	if (!l)
   1404 		return;
   1405 
   1406 	hdp_adapter = l->data;
   1407 	adapters = g_slist_remove(adapters, hdp_adapter);
   1408 	if (hdp_adapter->sdp_handler)
   1409 		remove_record_from_server(hdp_adapter->sdp_handler);
   1410 	release_adapter_instance(hdp_adapter);
   1411 	btd_adapter_unref(hdp_adapter->btd_adapter);
   1412 	g_free(hdp_adapter);
   1413 }
   1414 
   1415 static void delete_echo_channel_cb(GError *err, gpointer chan)
   1416 {
   1417 	if (err && err->code != MCAP_INVALID_MDL) {
   1418 		/* TODO: Decide if more action is required here */
   1419 		error("Error deleting echo channel: %s", err->message);
   1420 		return;
   1421 	}
   1422 
   1423 	health_channel_destroy(chan);
   1424 }
   1425 
   1426 static void delete_echo_channel(struct hdp_channel *chan)
   1427 {
   1428 	GError *err = NULL;
   1429 
   1430 	if (!chan->dev->mcl_conn) {
   1431 		error("Echo channel cannot be deleted: mcl closed");
   1432 		return;
   1433 	}
   1434 
   1435 	if (mcap_delete_mdl(chan->mdl, delete_echo_channel_cb,
   1436 				hdp_channel_ref(chan),
   1437 				(GDestroyNotify) hdp_channel_unref, &err))
   1438 		return;
   1439 
   1440 	hdp_channel_unref(chan);
   1441 	error("Error deleting the echo channel: %s", err->message);
   1442 	g_error_free(err);
   1443 
   1444 	/* TODO: Decide if more action is required here */
   1445 }
   1446 
   1447 static void abort_echo_channel_cb(GError *err, gpointer data)
   1448 {
   1449 	struct hdp_channel *chan = data;
   1450 
   1451 	if (err && err->code != MCAP_ERROR_INVALID_OPERATION) {
   1452 		error("Aborting error: %s", err->message);
   1453 		if (err->code == MCAP_INVALID_MDL) {
   1454 			/* MDL is removed from MCAP so we can */
   1455 			/* free the data channel without sending */
   1456 			/* a MD_DELETE_MDL_REQ */
   1457 			/* TODO review the above comment */
   1458 			/* hdp_channel_unref(chan); */
   1459 		}
   1460 		return;
   1461 	}
   1462 
   1463 	delete_echo_channel(chan);
   1464 }
   1465 
   1466 static void destroy_create_dc_data(gpointer data)
   1467 {
   1468 	struct hdp_create_dc *dc_data = data;
   1469 
   1470 	hdp_create_data_unref(dc_data);
   1471 }
   1472 
   1473 static void *generate_echo_packet(void)
   1474 {
   1475 	uint8_t *buf;
   1476 	int i;
   1477 
   1478 	buf = g_malloc(HDP_ECHO_LEN);
   1479 	srand(time(NULL));
   1480 
   1481 	for(i = 0; i < HDP_ECHO_LEN; i++)
   1482 		buf[i] = rand() % UINT8_MAX;
   1483 
   1484 	return buf;
   1485 }
   1486 
   1487 static gboolean check_echo(GIOChannel *io_chan, GIOCondition cond,
   1488 								gpointer data)
   1489 {
   1490 	struct hdp_tmp_dc_data *hdp_conn =  data;
   1491 	struct hdp_echo_data *edata = hdp_conn->hdp_chann->edata;
   1492 	struct hdp_channel *chan = hdp_conn->hdp_chann;
   1493 	uint8_t buf[MCAP_DC_MTU];
   1494 	DBusMessage *reply;
   1495 	gboolean value;
   1496 	int fd, len;
   1497 
   1498 	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
   1499 		value = FALSE;
   1500 		goto end;
   1501 	}
   1502 
   1503 	fd = g_io_channel_unix_get_fd(io_chan);
   1504 	len = read(fd, buf, sizeof(buf));
   1505 
   1506 	if (len != HDP_ECHO_LEN) {
   1507 		value = FALSE;
   1508 		goto end;
   1509 	}
   1510 
   1511 	value = (memcmp(buf, edata->buf, len) == 0);
   1512 
   1513 end:
   1514 	reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_BOOLEAN, &value,
   1515 							DBUS_TYPE_INVALID);
   1516 	g_dbus_send_message(hdp_conn->conn, reply);
   1517 	g_source_remove(edata->tid);
   1518 	edata->tid = 0;
   1519 	g_free(edata->buf);
   1520 	edata->buf = NULL;
   1521 
   1522 	if (!value)
   1523 		close_device_con(chan->dev, FALSE);
   1524 	else
   1525 		delete_echo_channel(chan);
   1526 	hdp_tmp_dc_data_unref(hdp_conn);
   1527 
   1528 	return FALSE;
   1529 }
   1530 
   1531 static gboolean echo_timeout(gpointer data)
   1532 {
   1533 	struct hdp_channel *chan = data;
   1534 	GIOChannel *io;
   1535 	int fd;
   1536 
   1537 	error("Error: Echo request timeout");
   1538 	chan->edata->tid = 0;
   1539 
   1540 	fd = mcap_mdl_get_fd(chan->mdl);
   1541 	if (fd < 0)
   1542 		return FALSE;
   1543 
   1544 	io = g_io_channel_unix_new(fd);
   1545 	g_io_channel_shutdown(io, TRUE, NULL);
   1546 
   1547 	return FALSE;
   1548 }
   1549 
   1550 static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
   1551 								gpointer data)
   1552 {
   1553 	struct hdp_tmp_dc_data *hdp_conn =  data;
   1554 	struct hdp_echo_data *edata;
   1555 	GError *gerr = NULL;
   1556 	DBusMessage *reply;
   1557 	GIOChannel *io;
   1558 	int fd;
   1559 
   1560 	if (err) {
   1561 		reply = g_dbus_create_error(hdp_conn->msg,
   1562 						ERROR_INTERFACE ".HealthError",
   1563 						"%s", err->message);
   1564 		g_dbus_send_message(hdp_conn->conn, reply);
   1565 
   1566 		/* Send abort request because remote */
   1567 		/* side is now in PENDING state. */
   1568 		if (!mcap_mdl_abort(hdp_conn->hdp_chann->mdl,
   1569 					abort_echo_channel_cb,
   1570 					hdp_channel_ref(hdp_conn->hdp_chann),
   1571 					(GDestroyNotify) hdp_channel_unref,
   1572 					&gerr)) {
   1573 			error("%s", gerr->message);
   1574 			g_error_free(gerr);
   1575 			hdp_channel_unref(hdp_conn->hdp_chann);
   1576 		}
   1577 		return;
   1578 	}
   1579 
   1580 	fd = mcap_mdl_get_fd(hdp_conn->hdp_chann->mdl);
   1581 	if (fd < 0) {
   1582 		reply = g_dbus_create_error(hdp_conn->msg,
   1583 						ERROR_INTERFACE ".HealthError",
   1584 						"Can't write in echo channel");
   1585 		g_dbus_send_message(hdp_conn->conn, reply);
   1586 		delete_echo_channel(hdp_conn->hdp_chann);
   1587 		return;
   1588 	}
   1589 
   1590 	edata = hdp_conn->hdp_chann->edata;
   1591 	edata->buf = generate_echo_packet();
   1592 	send_echo_data(fd, edata->buf, HDP_ECHO_LEN);
   1593 
   1594 	io = g_io_channel_unix_new(fd);
   1595 	g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
   1596 			check_echo, hdp_tmp_dc_data_ref(hdp_conn));
   1597 
   1598 	edata->tid  = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
   1599 					ECHO_TIMEOUT, echo_timeout,
   1600 					hdp_channel_ref(hdp_conn->hdp_chann),
   1601 					(GDestroyNotify) hdp_channel_unref);
   1602 
   1603 	g_io_channel_unref(io);
   1604 }
   1605 
   1606 static void delete_mdl_cb(GError *err, gpointer data)
   1607 {
   1608 	if (err)
   1609 		error("Deleting error: %s", err->message);
   1610 }
   1611 
   1612 static void abort_and_del_mdl_cb(GError *err, gpointer data)
   1613 {
   1614 	struct mcap_mdl *mdl = data;
   1615 	GError *gerr = NULL;
   1616 
   1617 	if (err) {
   1618 		error("%s", err->message);
   1619 		if (err->code == MCAP_INVALID_MDL) {
   1620 			/* MDL is removed from MCAP so we don't */
   1621 			/* need to delete it. */
   1622 			return;
   1623 		}
   1624 	}
   1625 
   1626 	if (!mcap_delete_mdl(mdl, delete_mdl_cb, NULL, NULL, &gerr)) {
   1627 		error("%s", gerr->message);
   1628 		g_error_free(gerr);
   1629 	}
   1630 }
   1631 
   1632 static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
   1633 {
   1634 	struct hdp_tmp_dc_data *hdp_conn =  data;
   1635 	struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
   1636 	struct hdp_device *dev = hdp_chann->dev;
   1637 	DBusMessage *reply;
   1638 	GError *gerr = NULL;
   1639 
   1640 	if (err) {
   1641 		error("%s", err->message);
   1642 		reply = g_dbus_create_reply(hdp_conn->msg,
   1643 					DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
   1644 					DBUS_TYPE_INVALID);
   1645 		g_dbus_send_message(hdp_conn->conn, reply);
   1646 
   1647 		/* Send abort request because remote side */
   1648 		/* is now in PENDING state */
   1649 		if (!mcap_mdl_abort(hdp_chann->mdl, abort_mdl_cb, NULL,
   1650 								NULL, &gerr)) {
   1651 			error("%s", gerr->message);
   1652 			g_error_free(gerr);
   1653 		}
   1654 		return;
   1655 	}
   1656 
   1657 	reply = g_dbus_create_reply(hdp_conn->msg,
   1658 					DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
   1659 					DBUS_TYPE_INVALID);
   1660 	g_dbus_send_message(hdp_conn->conn, reply);
   1661 
   1662 	if (!check_channel_conf(hdp_chann)) {
   1663 		close_mdl(hdp_chann);
   1664 		return;
   1665 	}
   1666 
   1667 	if (dev->fr)
   1668 		return;
   1669 
   1670 	dev->fr = hdp_channel_ref(hdp_chann);
   1671 
   1672 	emit_property_changed(dev->conn, device_get_path(dev->dev),
   1673 					HEALTH_DEVICE, "MainChannel",
   1674 					DBUS_TYPE_OBJECT_PATH, &dev->fr->path);
   1675 }
   1676 
   1677 static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
   1678 						GError *err, gpointer data)
   1679 {
   1680 	struct hdp_create_dc *user_data = data;
   1681 	struct hdp_tmp_dc_data *hdp_conn;
   1682 	struct hdp_channel *hdp_chan;
   1683 	GError *gerr = NULL;
   1684 	DBusMessage *reply;
   1685 
   1686 	if (err) {
   1687 		reply = g_dbus_create_error(user_data->msg,
   1688 					ERROR_INTERFACE ".HealthError",
   1689 					"%s", err->message);
   1690 		g_dbus_send_message(user_data->conn, reply);
   1691 		return;
   1692 	}
   1693 
   1694 	if (user_data->mdep != HDP_MDEP_ECHO &&
   1695 				user_data->config == HDP_NO_PREFERENCE_DC) {
   1696 		if (!user_data->dev->fr && (conf != HDP_RELIABLE_DC)) {
   1697 			g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
   1698 					"Data channel aborted, first data "
   1699 					"channel should be reliable");
   1700 			goto fail;
   1701 		} else if (conf == HDP_NO_PREFERENCE_DC ||
   1702 						conf > HDP_STREAMING_DC) {
   1703 			g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
   1704 							"Data channel aborted, "
   1705 							"configuration error");
   1706 			goto fail;
   1707 		}
   1708 	}
   1709 
   1710 	hdp_chan = create_channel(user_data->dev, conf, mdl,
   1711 							mcap_mdl_get_mdlid(mdl),
   1712 							user_data->app, &gerr);
   1713 	if (!hdp_chan)
   1714 		goto fail;
   1715 
   1716 	if (user_data->mdep != HDP_MDEP_ECHO)
   1717 		g_dbus_emit_signal(user_data->conn,
   1718 					device_get_path(hdp_chan->dev->dev),
   1719 					HEALTH_DEVICE,
   1720 					"ChannelConnected",
   1721 					DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
   1722 					DBUS_TYPE_INVALID);
   1723 
   1724 	hdp_conn = g_new0(struct hdp_tmp_dc_data, 1);
   1725 	hdp_conn->msg = dbus_message_ref(user_data->msg);
   1726 	hdp_conn->conn = dbus_connection_ref(user_data->conn);
   1727 	hdp_conn->hdp_chann = hdp_chan;
   1728 	hdp_conn->cb = user_data->cb;
   1729 	hdp_chan->mdep = user_data->mdep;
   1730 
   1731 	if (hdp_get_dcpsm(hdp_chan->dev, hdp_get_dcpsm_cb,
   1732 						hdp_tmp_dc_data_ref(hdp_conn),
   1733 						hdp_tmp_dc_data_destroy, &gerr))
   1734 		return;
   1735 
   1736 	error("%s", gerr->message);
   1737 	g_error_free(gerr);
   1738 
   1739 	reply = g_dbus_create_reply(hdp_conn->msg,
   1740 					DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
   1741 					DBUS_TYPE_INVALID);
   1742 	g_dbus_send_message(hdp_conn->conn, reply);
   1743 	hdp_tmp_dc_data_unref(hdp_conn);
   1744 
   1745 	/* Send abort request because remote side is now in PENDING state */
   1746 	if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) {
   1747 		error("%s", gerr->message);
   1748 		g_error_free(gerr);
   1749 	}
   1750 
   1751 	return;
   1752 
   1753 fail:
   1754 	reply = g_dbus_create_error(user_data->msg,
   1755 						ERROR_INTERFACE ".HealthError",
   1756 						"%s", gerr->message);
   1757 	g_dbus_send_message(user_data->conn, reply);
   1758 	g_error_free(gerr);
   1759 
   1760 	/* Send abort request because remote side is now in PENDING */
   1761 	/* state. Then we have to delete it because we couldn't */
   1762 	/* register the HealthChannel interface */
   1763 	if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl), NULL,
   1764 								&gerr)) {
   1765 		error("%s", gerr->message);
   1766 		g_error_free(gerr);
   1767 		mcap_mdl_unref(mdl);
   1768 	}
   1769 }
   1770 
   1771 static void device_create_dc_cb(gpointer user_data, GError *err)
   1772 {
   1773 	struct hdp_create_dc *data = user_data;
   1774 	DBusMessage *reply;
   1775 	GError *gerr = NULL;
   1776 
   1777 	if (err) {
   1778 		reply = g_dbus_create_error(data->msg,
   1779 					ERROR_INTERFACE ".HealthError",
   1780 					"%s", err->message);
   1781 		g_dbus_send_message(data->conn, reply);
   1782 		return;
   1783 	}
   1784 
   1785 	if (!data->dev->mcl) {
   1786 		g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
   1787 				"Mcl was closed");
   1788 		goto fail;
   1789 	}
   1790 
   1791 	hdp_create_data_ref(data);
   1792 
   1793 	if (mcap_create_mdl(data->dev->mcl, data->mdep, data->config,
   1794 						device_create_mdl_cb, data,
   1795 						destroy_create_dc_data, &gerr))
   1796 		return;
   1797 	hdp_create_data_unref(data);
   1798 
   1799 fail:
   1800 	reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
   1801 							"%s", gerr->message);
   1802 	g_error_free(gerr);
   1803 	g_dbus_send_message(data->conn, reply);
   1804 }
   1805 
   1806 static DBusMessage *device_echo(DBusConnection *conn,
   1807 					DBusMessage *msg, void *user_data)
   1808 {
   1809 	struct hdp_device *device = user_data;
   1810 	struct hdp_create_dc *data;
   1811 	DBusMessage *reply;
   1812 	GError *err = NULL;
   1813 
   1814 	data = g_new0(struct hdp_create_dc, 1);
   1815 	data->dev = health_device_ref(device);
   1816 	data->mdep = HDP_MDEP_ECHO;
   1817 	data->config = HDP_RELIABLE_DC;
   1818 	data->msg = dbus_message_ref(msg);
   1819 	data->conn = dbus_connection_ref(conn);
   1820 	data->cb = hdp_echo_connect_cb;
   1821 	hdp_create_data_ref(data);
   1822 
   1823 	if (device->mcl_conn && device->mcl) {
   1824 		if (mcap_create_mdl(device->mcl, data->mdep, data->config,
   1825 						device_create_mdl_cb, data,
   1826 						destroy_create_dc_data, &err))
   1827 			return NULL;
   1828 		goto fail;
   1829 	}
   1830 
   1831 	if (hdp_establish_mcl(data->dev, device_create_dc_cb,
   1832 					data, destroy_create_dc_data, &err))
   1833 		return NULL;
   1834 
   1835 fail:
   1836 	reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
   1837 							"%s", err->message);
   1838 	g_error_free(err);
   1839 	hdp_create_data_unref(data);
   1840 	return reply;
   1841 }
   1842 
   1843 static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
   1844 {
   1845 	struct hdp_create_dc *dc_data, *user_data = data;
   1846 	DBusMessage *reply;
   1847 	GError *gerr = NULL;
   1848 
   1849 	if (err) {
   1850 		reply = g_dbus_create_error(user_data->msg,
   1851 						ERROR_INTERFACE ".HealthError",
   1852 						"%s", err->message);
   1853 		g_dbus_send_message(user_data->conn, reply);
   1854 		return;
   1855 	}
   1856 
   1857 	dc_data = hdp_create_data_ref(user_data);
   1858 	dc_data->mdep = mdep;
   1859 
   1860 	if (user_data->dev->mcl_conn) {
   1861 		device_create_dc_cb(dc_data, NULL);
   1862 		hdp_create_data_unref(dc_data);
   1863 		return;
   1864 	}
   1865 
   1866 	if (hdp_establish_mcl(dc_data->dev, device_create_dc_cb,
   1867 					dc_data, destroy_create_dc_data, &gerr))
   1868 		return;
   1869 
   1870 	reply = g_dbus_create_error(user_data->msg,
   1871 						ERROR_INTERFACE ".HealthError",
   1872 						"%s", gerr->message);
   1873 	hdp_create_data_unref(dc_data);
   1874 	g_error_free(gerr);
   1875 	g_dbus_send_message(user_data->conn, reply);
   1876 }
   1877 
   1878 static DBusMessage *device_create_channel(DBusConnection *conn,
   1879 					DBusMessage *msg, void *user_data)
   1880 {
   1881 	struct hdp_device *device = user_data;
   1882 	struct hdp_application *app;
   1883 	struct hdp_create_dc *data;
   1884 	char *app_path, *conf;
   1885 	DBusMessage *reply;
   1886 	GError *err = NULL;
   1887 	uint8_t config;
   1888 	GSList *l;
   1889 
   1890 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &app_path,
   1891 							DBUS_TYPE_STRING, &conf,
   1892 							DBUS_TYPE_INVALID))
   1893 		return btd_error_invalid_args(msg);
   1894 
   1895 	l = g_slist_find_custom(applications, app_path, cmp_app);
   1896 	if (!l)
   1897 		return btd_error_invalid_args(msg);
   1898 
   1899 	app = l->data;
   1900 
   1901 	if (g_ascii_strcasecmp("Reliable", conf) == 0)
   1902 		config = HDP_RELIABLE_DC;
   1903 	else if (g_ascii_strcasecmp("Streaming", conf) == 0)
   1904 		config = HDP_STREAMING_DC;
   1905 	else if (g_ascii_strcasecmp("Any", conf) == 0)
   1906 		config = HDP_NO_PREFERENCE_DC;
   1907 	else
   1908 		return btd_error_invalid_args(msg);
   1909 
   1910 	if (app->role == HDP_SINK && config != HDP_NO_PREFERENCE_DC)
   1911 		return btd_error_invalid_args(msg);
   1912 
   1913 	if (app->role == HDP_SOURCE && config == HDP_NO_PREFERENCE_DC)
   1914 		return btd_error_invalid_args(msg);
   1915 
   1916 	if (!device->fr && config == HDP_STREAMING_DC)
   1917 		return btd_error_invalid_args(msg);
   1918 
   1919 	data = g_new0(struct hdp_create_dc, 1);
   1920 	data->dev = health_device_ref(device);
   1921 	data->config = config;
   1922 	data->app = hdp_application_ref(app);
   1923 	data->msg = dbus_message_ref(msg);
   1924 	data->conn = dbus_connection_ref(conn);
   1925 	data->cb = hdp_mdl_conn_cb;
   1926 
   1927 	if (hdp_get_mdep(device, l->data, device_get_mdep_cb,
   1928 						hdp_create_data_ref(data),
   1929 						destroy_create_dc_data, &err))
   1930 		return NULL;
   1931 
   1932 	reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
   1933 							"%s", err->message);
   1934 	g_error_free(err);
   1935 	hdp_create_data_unref(data);
   1936 	return reply;
   1937 }
   1938 
   1939 static void hdp_mdl_delete_cb(GError *err, gpointer data)
   1940 {
   1941 	struct hdp_tmp_dc_data *del_data = data;
   1942 	DBusMessage *reply;
   1943 	char *path;
   1944 
   1945 	if (err && err->code != MCAP_INVALID_MDL) {
   1946 		reply = g_dbus_create_error(del_data->msg,
   1947 						ERROR_INTERFACE ".HealthError",
   1948 						"%s", err->message);
   1949 		g_dbus_send_message(del_data->conn, reply);
   1950 		return;
   1951 	}
   1952 
   1953 	path = g_strdup(del_data->hdp_chann->path);
   1954 	g_dbus_unregister_interface(del_data->conn, path, HEALTH_CHANNEL);
   1955 	g_free(path);
   1956 
   1957 	reply = g_dbus_create_reply(del_data->msg, DBUS_TYPE_INVALID);
   1958 	g_dbus_send_message(del_data->conn, reply);
   1959 }
   1960 
   1961 static void hdp_continue_del_cb(gpointer user_data, GError *err)
   1962 {
   1963 	struct hdp_tmp_dc_data *del_data = user_data;
   1964 	GError *gerr = NULL;
   1965 	DBusMessage *reply;
   1966 
   1967 	if (err) {
   1968 		reply = g_dbus_create_error(del_data->msg,
   1969 					ERROR_INTERFACE ".HealthError",
   1970 					"%s", err->message);
   1971 		g_dbus_send_message(del_data->conn, reply);
   1972 		return;
   1973 	}
   1974 
   1975 	if (mcap_delete_mdl(del_data->hdp_chann->mdl, hdp_mdl_delete_cb,
   1976 						hdp_tmp_dc_data_ref(del_data),
   1977 						hdp_tmp_dc_data_destroy, &gerr))
   1978 			return;
   1979 
   1980 	reply = g_dbus_create_error(del_data->msg,
   1981 						ERROR_INTERFACE ".HealthError",
   1982 						"%s", gerr->message);
   1983 	hdp_tmp_dc_data_unref(del_data);
   1984 	g_error_free(gerr);
   1985 	g_dbus_send_message(del_data->conn, reply);
   1986 }
   1987 
   1988 static DBusMessage *device_destroy_channel(DBusConnection *conn,
   1989 					DBusMessage *msg, void *user_data)
   1990 {
   1991 	struct hdp_device *device = user_data;
   1992 	struct hdp_tmp_dc_data *del_data;
   1993 	struct hdp_channel *hdp_chan;
   1994 	DBusMessage *reply;
   1995 	GError *err = NULL;
   1996 	char *path;
   1997 	GSList *l;
   1998 
   1999 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
   2000 							DBUS_TYPE_INVALID)){
   2001 		return btd_error_invalid_args(msg);
   2002 	}
   2003 
   2004 	l = g_slist_find_custom(device->channels, path, cmp_chan_path);
   2005 	if (!l)
   2006 		return btd_error_invalid_args(msg);
   2007 
   2008 	hdp_chan = l->data;
   2009 	del_data = g_new0(struct hdp_tmp_dc_data, 1);
   2010 	del_data->msg = dbus_message_ref(msg);
   2011 	del_data->conn = dbus_connection_ref(conn);
   2012 	del_data->hdp_chann = hdp_channel_ref(hdp_chan);
   2013 
   2014 	if (device->mcl_conn) {
   2015 		if (mcap_delete_mdl(hdp_chan->mdl, hdp_mdl_delete_cb,
   2016 						hdp_tmp_dc_data_ref(del_data),
   2017 						hdp_tmp_dc_data_destroy, &err))
   2018 			return NULL;
   2019 		goto fail;
   2020 	}
   2021 
   2022 	if (hdp_establish_mcl(device, hdp_continue_del_cb,
   2023 						hdp_tmp_dc_data_ref(del_data),
   2024 						hdp_tmp_dc_data_destroy, &err))
   2025 		return NULL;
   2026 
   2027 fail:
   2028 	reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
   2029 							"%s", err->message);
   2030 	hdp_tmp_dc_data_unref(del_data);
   2031 	g_error_free(err);
   2032 	return reply;
   2033 }
   2034 
   2035 static DBusMessage *device_get_properties(DBusConnection *conn,
   2036 					DBusMessage *msg, void *user_data)
   2037 {
   2038 	struct hdp_device *device = user_data;
   2039 	DBusMessageIter iter, dict;
   2040 	DBusMessage *reply;
   2041 	char *path;
   2042 
   2043 	reply = dbus_message_new_method_return(msg);
   2044 	if (!reply)
   2045 		return NULL;
   2046 
   2047 	dbus_message_iter_init_append(reply, &iter);
   2048 
   2049 	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
   2050 			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
   2051 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
   2052 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
   2053 
   2054 	if (device->fr)
   2055 		path = g_strdup(device->fr->path);
   2056 	else
   2057 		path = g_strdup("");
   2058 	dict_append_entry(&dict, "MainChannel", DBUS_TYPE_OBJECT_PATH, &path);
   2059 	g_free(path);
   2060 	dbus_message_iter_close_container(&iter, &dict);
   2061 
   2062 	return reply;
   2063 }
   2064 
   2065 static void health_device_destroy(void *data)
   2066 {
   2067 	struct hdp_device *device = data;
   2068 
   2069 	DBG("Unregistered interface %s on path %s", HEALTH_DEVICE,
   2070 						device_get_path(device->dev));
   2071 
   2072 	remove_channels(device);
   2073 	if (device->ndc) {
   2074 		hdp_channel_unref(device->ndc);
   2075 		device->ndc = NULL;
   2076 	}
   2077 
   2078 	devices = g_slist_remove(devices, device);
   2079 	health_device_unref(device);
   2080 }
   2081 
   2082 static GDBusMethodTable health_device_methods[] = {
   2083 	{"Echo",		"",	"b",	device_echo,
   2084 						G_DBUS_METHOD_FLAG_ASYNC },
   2085 	{"CreateChannel",	"os",	"o",	device_create_channel,
   2086 						G_DBUS_METHOD_FLAG_ASYNC },
   2087 	{"DestroyChannel",	"o",	"",	device_destroy_channel,
   2088 						G_DBUS_METHOD_FLAG_ASYNC },
   2089 	{"GetProperties",	"",	"a{sv}", device_get_properties},
   2090 	{ NULL }
   2091 };
   2092 
   2093 static GDBusSignalTable health_device_signals[] = {
   2094 	{"ChannelConnected",		"o"		},
   2095 	{"ChannelDeleted",		"o"		},
   2096 	{"PropertyChanged",		"sv"		},
   2097 	{ NULL }
   2098 };
   2099 
   2100 static struct hdp_device *create_health_device(DBusConnection *conn,
   2101 						struct btd_device *device)
   2102 {
   2103 	struct btd_adapter *adapter = device_get_adapter(device);
   2104 	const gchar *path = device_get_path(device);
   2105 	struct hdp_device *dev;
   2106 	GSList *l;
   2107 
   2108 	if (!device)
   2109 		return NULL;
   2110 
   2111 	dev = g_new0(struct hdp_device, 1);
   2112 	dev->conn = dbus_connection_ref(conn);
   2113 	dev->dev = btd_device_ref(device);
   2114 	health_device_ref(dev);
   2115 
   2116 	l = g_slist_find_custom(adapters, adapter, cmp_adapter);
   2117 	if (!l)
   2118 		goto fail;
   2119 
   2120 	dev->hdp_adapter = l->data;
   2121 
   2122 	if (!g_dbus_register_interface(conn, path,
   2123 					HEALTH_DEVICE,
   2124 					health_device_methods,
   2125 					health_device_signals, NULL,
   2126 					dev, health_device_destroy)) {
   2127 		error("D-Bus failed to register %s interface", HEALTH_DEVICE);
   2128 		goto fail;
   2129 	}
   2130 
   2131 	DBG("Registered interface %s on path %s", HEALTH_DEVICE, path);
   2132 	return dev;
   2133 
   2134 fail:
   2135 	health_device_unref(dev);
   2136 	return NULL;
   2137 }
   2138 
   2139 int hdp_device_register(DBusConnection *conn, struct btd_device *device)
   2140 {
   2141 	struct hdp_device *hdev;
   2142 	GSList *l;
   2143 
   2144 	l = g_slist_find_custom(devices, device, cmp_device);
   2145 	if (l) {
   2146 		hdev = l->data;
   2147 		hdev->sdp_present = TRUE;
   2148 		return 0;
   2149 	}
   2150 
   2151 	hdev = create_health_device(conn, device);
   2152 	if (!hdev)
   2153 		return -1;
   2154 
   2155 	hdev->sdp_present = TRUE;
   2156 
   2157 	devices = g_slist_prepend(devices, hdev);
   2158 	return 0;
   2159 }
   2160 
   2161 void hdp_device_unregister(struct btd_device *device)
   2162 {
   2163 	struct hdp_device *hdp_dev;
   2164 	const char *path;
   2165 	GSList *l;
   2166 
   2167 	l = g_slist_find_custom(devices, device, cmp_device);
   2168 	if (!l)
   2169 		return;
   2170 
   2171 	hdp_dev = l->data;
   2172 	path = device_get_path(hdp_dev->dev);
   2173 	g_dbus_unregister_interface(hdp_dev->conn, path, HEALTH_DEVICE);
   2174 }
   2175 
   2176 int hdp_manager_start(DBusConnection *conn)
   2177 {
   2178 	DBG("Starting Health manager");
   2179 
   2180 	if (!g_dbus_register_interface(conn, MANAGER_PATH,
   2181 					HEALTH_MANAGER,
   2182 					health_manager_methods, NULL, NULL,
   2183 					NULL, manager_path_unregister)) {
   2184 		error("D-Bus failed to register %s interface", HEALTH_MANAGER);
   2185 		return -1;
   2186 	}
   2187 
   2188 	connection = dbus_connection_ref(conn);
   2189 
   2190 	return 0;
   2191 }
   2192 
   2193 void hdp_manager_stop(void)
   2194 {
   2195 	g_dbus_unregister_interface(connection, MANAGER_PATH, HEALTH_MANAGER);
   2196 
   2197 	dbus_connection_unref(connection);
   2198 	DBG("Stopped Health manager");
   2199 }
   2200 
   2201 struct hdp_device *health_device_ref(struct hdp_device *hdp_dev)
   2202 {
   2203 	hdp_dev->ref++;
   2204 
   2205 	DBG("health_device_ref(%p): ref=%d", hdp_dev, hdp_dev->ref);
   2206 
   2207 	return hdp_dev;
   2208 }
   2209 
   2210 void health_device_unref(struct hdp_device *hdp_dev)
   2211 {
   2212 	hdp_dev->ref--;
   2213 
   2214 	DBG("health_device_unref(%p): ref=%d", hdp_dev, hdp_dev->ref);
   2215 
   2216 	if (hdp_dev->ref > 0)
   2217 		return;
   2218 
   2219 	free_health_device(hdp_dev);
   2220 }
   2221