• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
hdp_channel_ref(struct hdp_channel * chan)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 
free_health_channel(struct hdp_channel * chan)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 
hdp_channel_unref(struct hdp_channel * chan)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 
free_hdp_create_dc(struct hdp_create_dc * dc_data)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 
hdp_create_data_ref(struct hdp_create_dc * dc_data)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 
hdp_create_data_unref(struct hdp_create_dc * dc_data)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 
free_hdp_conn_dc(struct hdp_tmp_dc_data * data)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 
hdp_tmp_dc_data_ref(struct hdp_tmp_dc_data * data)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 
hdp_tmp_dc_data_unref(struct hdp_tmp_dc_data * data)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 
cmp_app_id(gconstpointer a,gconstpointer b)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 
cmp_adapter(gconstpointer a,gconstpointer b)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 
cmp_device(gconstpointer a,gconstpointer b)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 
cmp_dev_addr(gconstpointer a,gconstpointer dst)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 
cmp_dev_mcl(gconstpointer a,gconstpointer mcl)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 
cmp_chan_mdlid(gconstpointer a,gconstpointer b)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 
cmp_chan_path(gconstpointer a,gconstpointer b)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 
cmp_chan_mdl(gconstpointer a,gconstpointer mdl)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 
get_app_id(void)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 
cmp_app(gconstpointer a,gconstpointer b)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 
set_app_path(struct hdp_application * app)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 
device_unref_mcl(struct hdp_device * hdp_device)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 
free_health_device(struct hdp_device * device)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 
remove_application(struct hdp_application * app)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 
client_disconnected(DBusConnection * conn,void * user_data)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 
manager_create_application(DBusConnection * conn,DBusMessage * msg,void * user_data)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 
manager_destroy_application(DBusConnection * conn,DBusMessage * msg,void * user_data)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 
manager_path_unregister(gpointer data)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 
channel_get_properties(DBusConnection * conn,DBusMessage * msg,void * user_data)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 
hdp_tmp_dc_data_destroy(gpointer data)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 
abort_mdl_cb(GError * err,gpointer data)480 static 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 
hdp_mdl_reconn_cb(struct mcap_mdl * mdl,GError * err,gpointer data)500 static 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 
hdp_get_dcpsm_cb(uint16_t dcpsm,gpointer user_data,GError * err)546 static 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 
device_reconnect_mdl_cb(struct mcap_mdl * mdl,GError * err,gpointer data)574 static 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 
channel_acquire_continue(struct hdp_tmp_dc_data * data,GError * err)612 static 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 
channel_acquire_cb(gpointer data,GError * err)643 static 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 
channel_acquire(DBusConnection * conn,DBusMessage * msg,void * user_data)654 static 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 
close_mdl(struct hdp_channel * hdp_chann)687 static 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 
channel_release(DBusConnection * conn,DBusMessage * msg,void * user_data)698 static 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 
free_echo_data(struct hdp_echo_data * edata)708 static 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 
health_channel_destroy(void * data)723 static 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 
751 end:
752 	hdp_channel_unref(hdp_chan);
753 }
754 
755 static 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 
create_channel(struct hdp_device * dev,uint8_t config,struct mcap_mdl * mdl,uint16_t mdlid,struct hdp_application * app,GError ** err)763 static 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 
remove_channels(struct hdp_device * dev)812 static 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 
close_device_con(struct hdp_device * dev,gboolean cache)828 static 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 
send_echo_data(int sock,const void * buf,uint32_t size)850 static 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 
serve_echo(GIOChannel * io_chan,GIOCondition cond,gpointer data)865 static 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 
888 fail:
889 	close_device_con(chan->dev, FALSE);
890 	hdp_channel_unref(chan);
891 	return FALSE;
892 }
893 
check_channel_conf(struct hdp_channel * chan)894 static 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 
hdp_mcap_mdl_connected_cb(struct mcap_mdl * mdl,void * data)948 static 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 
1000 end:
1001 	hdp_channel_unref(dev->ndc);
1002 	dev->ndc = NULL;
1003 }
1004 
hdp_mcap_mdl_closed_cb(struct mcap_mdl * mdl,void * data)1005 static 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 
hdp_mcap_mdl_deleted_cb(struct mcap_mdl * mdl,void * data)1014 static 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 
hdp_mcap_mdl_aborted_cb(struct mcap_mdl * mdl,void * data)1034 static 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 
hdp2l2cap_mode(uint8_t hdp_mode)1058 static 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 
hdp_mcap_mdl_conn_req_cb(struct mcap_mcl * mcl,uint8_t mdepid,uint16_t mdlid,uint8_t * conf,void * data)1064 static 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 
hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl * mdl,void * data)1160 static 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 
hdp_set_mcl_cb(struct hdp_device * device,GError ** err)1189 gboolean 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 
mcl_connected(struct mcap_mcl * mcl,gpointer data)1214 static 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 
mcl_reconnected(struct mcap_mcl * mcl,gpointer data)1247 static 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 
mcl_disconnected(struct mcap_mcl * mcl,gpointer data)1264 static 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 
mcl_uncached(struct mcap_mcl * mcl,gpointer data)1279 static 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 
check_devices_mcl(void)1304 static 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 
release_adapter_instance(struct hdp_adapter * hdp_adapter)1329 static 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 
update_adapter(struct hdp_adapter * hdp_adapter)1340 static 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 
1378 update:
1379 	if (hdp_update_sdp_record(hdp_adapter, applications))
1380 		return TRUE;
1381 	error("Error updating the SDP record");
1382 
1383 fail:
1384 	release_adapter_instance(hdp_adapter);
1385 	if (err)
1386 		g_error_free(err);
1387 	return FALSE;
1388 }
1389 
hdp_adapter_register(DBusConnection * conn,struct btd_adapter * adapter)1390 int 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 
1404 fail:
1405 	btd_adapter_unref(hdp_adapter->btd_adapter);
1406 	g_free(hdp_adapter);
1407 	return -1;
1408 }
1409 
hdp_adapter_unregister(struct btd_adapter * adapter)1410 void 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 
delete_echo_channel_cb(GError * err,gpointer chan)1429 static 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 
delete_echo_channel(struct hdp_channel * chan)1440 static 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 
abort_echo_channel_cb(GError * err,gpointer data)1461 static 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 
destroy_create_dc_data(gpointer data)1480 static 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 
generate_echo_packet(void)1487 static 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 
check_echo(GIOChannel * io_chan,GIOCondition cond,gpointer data)1501 static 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 
1527 end:
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 
echo_timeout(gpointer data)1545 static 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 
hdp_echo_connect_cb(struct mcap_mdl * mdl,GError * err,gpointer data)1564 static 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 
delete_mdl_cb(GError * err,gpointer data)1620 static void delete_mdl_cb(GError *err, gpointer data)
1621 {
1622 	if (err)
1623 		error("Deleting error: %s", err->message);
1624 }
1625 
abort_and_del_mdl_cb(GError * err,gpointer data)1626 static 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 
hdp_mdl_conn_cb(struct mcap_mdl * mdl,GError * err,gpointer data)1646 static 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 
device_create_mdl_cb(struct mcap_mdl * mdl,uint8_t conf,GError * err,gpointer data)1700 static 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 
1768 fail:
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 
device_create_dc_cb(gpointer user_data,GError * err)1786 static 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 
1814 fail:
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 
device_echo(DBusConnection * conn,DBusMessage * msg,void * user_data)1821 static 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 
1850 fail:
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 
device_get_mdep_cb(uint8_t mdep,gpointer data,GError * err)1858 static 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 
device_create_channel(DBusConnection * conn,DBusMessage * msg,void * user_data)1893 static 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 
hdp_mdl_delete_cb(GError * err,gpointer data)1954 static 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 
hdp_continue_del_cb(gpointer user_data,GError * err)1976 static 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 
device_destroy_channel(DBusConnection * conn,DBusMessage * msg,void * user_data)2003 static 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 
2042 fail:
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 
device_get_properties(DBusConnection * conn,DBusMessage * msg,void * user_data)2050 static 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 
health_device_destroy(void * data)2080 static 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 
2097 static 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 
2108 static GDBusSignalTable health_device_signals[] = {
2109 	{"ChannelConnected",		"o"		},
2110 	{"ChannelDeleted",		"o"		},
2111 	{"PropertyChanged",		"sv"		},
2112 	{ NULL }
2113 };
2114 
create_health_device(DBusConnection * conn,struct btd_device * device)2115 static 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 
2149 fail:
2150 	health_device_unref(dev);
2151 	return NULL;
2152 }
2153 
hdp_device_register(DBusConnection * conn,struct btd_device * device)2154 int 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 
hdp_device_unregister(struct btd_device * device)2176 void 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 
hdp_manager_start(DBusConnection * conn)2191 int 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 
hdp_manager_stop(void)2208 void 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 
health_device_ref(struct hdp_device * hdp_dev)2216 struct 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 
health_device_unref(struct hdp_device * hdp_dev)2225 void 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