1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * BlueZ - Bluetooth protocol stack for Linux
6 * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
18 #include <sys/random.h>
22 #include "lib/bluetooth.h"
23 #include "lib/l2cap.h"
26 #include "gdbus/gdbus.h"
28 #include "src/dbus-common.h"
30 #include "src/error.h"
31 #include "src/adapter.h"
32 #include "src/device.h"
34 #include "src/shared/timeout.h"
35 #include "btio/btio.h"
37 #include "hdp_types.h"
42 #define ECHO_TIMEOUT 1 /* second */
43 #define HDP_ECHO_LEN 15
45 static GSList *applications = NULL;
46 static GSList *devices = NULL;
47 static uint8_t next_app_id = HDP_MDEP_INITIAL;
49 static GSList *adapters;
51 static struct hdp_device *create_health_device(struct btd_device *device);
52 static void free_echo_data(struct hdp_echo_data *edata);
54 struct hdp_create_dc {
56 struct hdp_application *app;
57 struct hdp_device *dev;
61 mcap_mdl_operation_cb cb;
64 struct hdp_tmp_dc_data {
66 struct hdp_channel *hdp_chann;
68 mcap_mdl_operation_cb cb;
71 struct hdp_echo_data {
72 gboolean echo_done; /* Is a echo was already done */
73 gpointer buf; /* echo packet sent */
74 unsigned int tid; /* echo timeout */
77 static struct hdp_channel *hdp_channel_ref(struct hdp_channel *chan)
84 DBG("(%p): ref=%d", chan, chan->ref);
88 static void free_health_channel(struct hdp_channel *chan)
90 if (chan->mdep == HDP_MDEP_ECHO) {
91 free_echo_data(chan->edata);
95 mcap_mdl_unref(chan->mdl);
96 hdp_application_unref(chan->app);
97 health_device_unref(chan->dev);
102 static void hdp_channel_unref(struct hdp_channel *chan)
108 DBG("(%p): ref=%d", chan, chan->ref);
113 free_health_channel(chan);
116 static void free_hdp_create_dc(struct hdp_create_dc *dc_data)
118 dbus_message_unref(dc_data->msg);
119 hdp_application_unref(dc_data->app);
120 health_device_unref(dc_data->dev);
125 static struct hdp_create_dc *hdp_create_data_ref(struct hdp_create_dc *dc_data)
129 DBG("(%p): ref=%d", dc_data, dc_data->ref);
134 static void hdp_create_data_unref(struct hdp_create_dc *dc_data)
138 DBG("(%p): ref=%d", dc_data, dc_data->ref);
140 if (dc_data->ref > 0)
143 free_hdp_create_dc(dc_data);
146 static void free_hdp_conn_dc(struct hdp_tmp_dc_data *data)
148 dbus_message_unref(data->msg);
149 hdp_channel_unref(data->hdp_chann);
154 static struct hdp_tmp_dc_data *hdp_tmp_dc_data_ref(struct hdp_tmp_dc_data *data)
158 DBG("hdp_conn_data_ref(%p): ref=%d", data, data->ref);
163 static void hdp_tmp_dc_data_unref(struct hdp_tmp_dc_data *data)
167 DBG("hdp_conn_data_unref(%p): ref=%d", data, data->ref);
172 free_hdp_conn_dc(data);
175 static int cmp_app_id(gconstpointer a, gconstpointer b)
177 const struct hdp_application *app = a;
178 const uint8_t *id = b;
180 return app->id - *id;
183 static int cmp_adapter(gconstpointer a, gconstpointer b)
185 const struct hdp_adapter *hdp_adapter = a;
186 const struct btd_adapter *adapter = b;
188 if (hdp_adapter->btd_adapter == adapter)
194 static int cmp_device(gconstpointer a, gconstpointer b)
196 const struct hdp_device *hdp_device = a;
197 const struct btd_device *device = b;
199 if (hdp_device->dev == device)
205 static int cmp_dev_addr(gconstpointer a, gconstpointer dst)
207 const struct hdp_device *device = a;
209 return bacmp(device_get_address(device->dev), dst);
212 static int cmp_dev_mcl(gconstpointer a, gconstpointer mcl)
214 const struct hdp_device *device = a;
216 if (mcl == device->mcl)
221 static int cmp_chan_mdlid(gconstpointer a, gconstpointer b)
223 const struct hdp_channel *chan = a;
224 const uint16_t *mdlid = b;
226 return chan->mdlid - *mdlid;
229 static int cmp_chan_path(gconstpointer a, gconstpointer b)
231 const struct hdp_channel *chan = a;
232 const char *path = b;
234 return g_ascii_strcasecmp(chan->path, path);
237 static int cmp_chan_mdl(gconstpointer a, gconstpointer mdl)
239 const struct hdp_channel *chan = a;
241 if (chan->mdl == mdl)
246 static uint8_t get_app_id(void)
248 uint8_t id = next_app_id;
251 GSList *l = g_slist_find_custom(applications, &id, cmp_app_id);
254 next_app_id = (id % HDP_MDEP_FINAL) + 1;
257 id = (id % HDP_MDEP_FINAL) + 1;
258 } while (id != next_app_id);
260 /* No more ids available */
264 static int cmp_app(gconstpointer a, gconstpointer b)
266 const struct hdp_application *app = a;
268 return g_strcmp0(app->path, b);
271 static gboolean set_app_path(struct hdp_application *app)
273 app->id = get_app_id();
276 app->path = g_strdup_printf(MANAGER_PATH "/health_app_%d", app->id);
281 static void device_unref_mcl(struct hdp_device *hdp_device)
283 if (hdp_device->mcl == NULL)
286 mcap_close_mcl(hdp_device->mcl, FALSE);
287 mcap_mcl_unref(hdp_device->mcl);
288 hdp_device->mcl = NULL;
289 hdp_device->mcl_conn = FALSE;
292 static void free_health_device(struct hdp_device *device)
294 if (device->dev != NULL) {
295 btd_device_unref(device->dev);
299 device_unref_mcl(device);
304 static void update_adapter_cb(void *data, void *user_data);
306 static void remove_application(struct hdp_application *app)
308 DBG("Application %s deleted", app->path);
309 hdp_application_unref(app);
311 g_slist_foreach(adapters, update_adapter_cb, NULL);
314 static void client_disconnected(DBusConnection *conn, void *user_data)
316 struct hdp_application *app = user_data;
318 DBG("Client disconnected from the bus, deleting hdp application");
319 applications = g_slist_remove(applications, app);
321 app->dbus_watcher = 0; /* Watcher shouldn't be freed in this case */
322 remove_application(app);
325 static DBusMessage *manager_create_application(DBusConnection *conn,
326 DBusMessage *msg, void *user_data)
328 struct hdp_application *app;
330 DBusMessageIter iter;
333 dbus_message_iter_init(msg, &iter);
334 app = hdp_get_app_config(&iter, &err);
337 return btd_error_invalid_args(msg);
340 name = dbus_message_get_sender(msg);
342 hdp_application_unref(app);
343 return g_dbus_create_error(msg,
344 ERROR_INTERFACE ".HealthError",
345 "Can't get sender name");
348 if (!set_app_path(app)) {
349 hdp_application_unref(app);
350 return g_dbus_create_error(msg,
351 ERROR_INTERFACE ".HealthError",
352 "Can't get a valid id for the application");
355 app->oname = g_strdup(name);
357 applications = g_slist_prepend(applications, app);
360 g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
361 name, client_disconnected, app, NULL);
362 g_slist_foreach(adapters, update_adapter_cb, NULL);
364 DBG("Health application created with id %s", app->path);
366 return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &app->path,
370 static DBusMessage *manager_destroy_application(DBusConnection *conn,
371 DBusMessage *msg, void *user_data)
374 struct hdp_application *app;
377 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
379 return btd_error_invalid_args(msg);
381 l = g_slist_find_custom(applications, path, cmp_app);
384 return g_dbus_create_error(msg,
385 ERROR_INTERFACE ".InvalidArguments",
386 "Invalid arguments in method call, "
387 "no such application");
390 applications = g_slist_remove(applications, app);
392 remove_application(app);
394 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
397 static void application_unref(void *data, void *user_data)
399 hdp_application_unref(data);
402 static void manager_path_unregister(gpointer data)
404 g_slist_foreach(applications, application_unref, NULL);
406 g_slist_free(applications);
409 g_slist_foreach(adapters, update_adapter_cb, NULL);
412 static const GDBusMethodTable health_manager_methods[] = {
413 { GDBUS_METHOD("CreateApplication",
414 GDBUS_ARGS({ "config", "a{sv}" }),
415 GDBUS_ARGS({ "application", "o" }),
416 manager_create_application) },
417 { GDBUS_METHOD("DestroyApplication",
418 GDBUS_ARGS({ "application", "o" }), NULL,
419 manager_destroy_application) },
423 static gboolean channel_property_get_device(const GDBusPropertyTable *property,
424 DBusMessageIter *iter, void *data)
426 struct hdp_channel *chan = data;
427 const char *path = device_get_path(chan->dev->dev);
429 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
434 static gboolean channel_property_get_application(
435 const GDBusPropertyTable *property,
436 DBusMessageIter *iter, void *data)
438 struct hdp_channel *chan = data;
439 const char *path = chan->app->path;
441 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
446 static gboolean channel_property_get_type(const GDBusPropertyTable *property,
447 DBusMessageIter *iter, void *data)
449 struct hdp_channel *chan = data;
452 if (chan->config == HDP_RELIABLE_DC)
457 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &type);
462 static void hdp_tmp_dc_data_destroy(gpointer data)
464 struct hdp_tmp_dc_data *hdp_conn = data;
466 hdp_tmp_dc_data_unref(hdp_conn);
469 static void abort_mdl_cb(GError *err, gpointer data)
472 error("Aborting error: %s", err->message);
475 static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
477 DBusConnection *conn = btd_get_dbus_connection();
478 struct hdp_tmp_dc_data *dc_data = data;
483 struct hdp_channel *chan = dc_data->hdp_chann;
486 error("%s", err->message);
487 reply = g_dbus_create_error(dc_data->msg,
488 ERROR_INTERFACE ".HealthError",
489 "Cannot reconnect: %s", err->message);
490 g_dbus_send_message(conn, reply);
492 /* Send abort request because remote side */
493 /* is now in PENDING state */
494 if (!mcap_mdl_abort(chan->mdl, abort_mdl_cb, NULL, NULL,
496 error("%s", gerr->message);
502 fd = mcap_mdl_get_fd(dc_data->hdp_chann->mdl);
504 reply = g_dbus_create_error(dc_data->msg,
505 ERROR_INTERFACE ".HealthError",
506 "Cannot get file descriptor");
507 g_dbus_send_message(conn, reply);
511 reply = g_dbus_create_reply(dc_data->msg, DBUS_TYPE_UNIX_FD,
512 &fd, DBUS_TYPE_INVALID);
513 g_dbus_send_message(conn, reply);
515 g_dbus_emit_signal(conn, device_get_path(dc_data->hdp_chann->dev->dev),
516 HEALTH_DEVICE, "ChannelConnected",
517 DBUS_TYPE_OBJECT_PATH, &dc_data->hdp_chann->path,
521 static void hdp_get_dcpsm_cb(uint16_t dcpsm, gpointer user_data, GError *err)
523 struct hdp_tmp_dc_data *hdp_conn = user_data;
524 struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
529 hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
533 if (hdp_chann->config == HDP_RELIABLE_DC)
534 mode = BT_IO_MODE_ERTM;
536 mode = BT_IO_MODE_STREAMING;
538 if (mcap_connect_mdl(hdp_chann->mdl, mode, dcpsm, hdp_conn->cb,
539 hdp_tmp_dc_data_ref(hdp_conn),
540 hdp_tmp_dc_data_destroy, &gerr))
543 hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
545 hdp_tmp_dc_data_unref(hdp_conn);
548 static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
551 DBusConnection *conn = btd_get_dbus_connection();
552 struct hdp_tmp_dc_data *dc_data = data;
557 reply = g_dbus_create_error(dc_data->msg,
558 ERROR_INTERFACE ".HealthError",
559 "Cannot reconnect: %s", err->message);
560 g_dbus_send_message(conn, reply);
564 dc_data->cb = hdp_mdl_reconn_cb;
566 if (hdp_get_dcpsm(dc_data->hdp_chann->dev, hdp_get_dcpsm_cb,
567 hdp_tmp_dc_data_ref(dc_data),
568 hdp_tmp_dc_data_destroy, &gerr))
571 error("%s", gerr->message);
573 reply = g_dbus_create_error(dc_data->msg,
574 ERROR_INTERFACE ".HealthError",
575 "Cannot reconnect: %s", gerr->message);
576 g_dbus_send_message(conn, reply);
577 hdp_tmp_dc_data_unref(dc_data);
580 /* Send abort request because remote side is now in PENDING state */
581 if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) {
582 error("%s", gerr->message);
587 static DBusMessage *channel_acquire_continue(struct hdp_tmp_dc_data *data,
595 return g_dbus_create_error(data->msg,
596 ERROR_INTERFACE ".HealthError",
600 fd = mcap_mdl_get_fd(data->hdp_chann->mdl);
602 return g_dbus_create_reply(data->msg, DBUS_TYPE_UNIX_FD, &fd,
605 hdp_tmp_dc_data_ref(data);
606 if (mcap_reconnect_mdl(data->hdp_chann->mdl, device_reconnect_mdl_cb,
607 data, hdp_tmp_dc_data_destroy, &gerr))
610 reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
611 "Cannot reconnect: %s", gerr->message);
613 hdp_tmp_dc_data_unref(data);
618 static void channel_acquire_cb(gpointer data, GError *err)
622 reply = channel_acquire_continue(data, err);
625 g_dbus_send_message(btd_get_dbus_connection(), reply);
628 static DBusMessage *channel_acquire(DBusConnection *conn,
629 DBusMessage *msg, void *user_data)
631 struct hdp_channel *chan = user_data;
632 struct hdp_tmp_dc_data *dc_data;
636 dc_data = g_new0(struct hdp_tmp_dc_data, 1);
637 dc_data->msg = dbus_message_ref(msg);
638 dc_data->hdp_chann = hdp_channel_ref(chan);
640 if (chan->dev->mcl_conn) {
641 reply = channel_acquire_continue(hdp_tmp_dc_data_ref(dc_data),
643 hdp_tmp_dc_data_unref(dc_data);
647 if (hdp_establish_mcl(chan->dev, channel_acquire_cb,
648 hdp_tmp_dc_data_ref(dc_data),
649 hdp_tmp_dc_data_destroy, &gerr))
652 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
653 "%s", gerr->message);
654 hdp_tmp_dc_data_unref(dc_data);
660 static void close_mdl(struct hdp_channel *hdp_chann)
664 fd = mcap_mdl_get_fd(hdp_chann->mdl);
671 static DBusMessage *channel_release(DBusConnection *conn,
672 DBusMessage *msg, void *user_data)
674 struct hdp_channel *hdp_chann = user_data;
676 close_mdl(hdp_chann);
678 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
681 static void free_echo_data(struct hdp_echo_data *edata)
687 timeout_remove(edata->tid);
689 if (edata->buf != NULL)
696 static void health_channel_destroy(void *data)
698 struct hdp_channel *hdp_chan = data;
699 struct hdp_device *dev = hdp_chan->dev;
701 DBG("Destroy Health Channel %s", hdp_chan->path);
702 if (g_slist_find(dev->channels, hdp_chan) == NULL)
705 dev->channels = g_slist_remove(dev->channels, hdp_chan);
707 if (hdp_chan->mdep != HDP_MDEP_ECHO)
708 g_dbus_emit_signal(btd_get_dbus_connection(),
709 device_get_path(dev->dev),
710 HEALTH_DEVICE, "ChannelDeleted",
711 DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
714 if (hdp_chan == dev->fr) {
715 hdp_channel_unref(dev->fr);
720 hdp_channel_unref(hdp_chan);
723 static const GDBusMethodTable health_channels_methods[] = {
724 { GDBUS_ASYNC_METHOD("Acquire",
725 NULL, GDBUS_ARGS({ "fd", "h" }),
727 { GDBUS_METHOD("Release", NULL, NULL, channel_release) },
731 static const GDBusPropertyTable health_channels_properties[] = {
732 { "Device", "o", channel_property_get_device },
733 { "Application", "o", channel_property_get_application },
734 { "Type", "s", channel_property_get_type },
738 static struct hdp_channel *create_channel(struct hdp_device *dev,
740 struct mcap_mdl *mdl,
742 struct hdp_application *app,
745 struct hdp_channel *hdp_chann;
748 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
749 "HDP device uninitialized");
753 hdp_chann = g_new0(struct hdp_channel, 1);
754 hdp_chann->config = config;
755 hdp_chann->dev = health_device_ref(dev);
756 hdp_chann->mdlid = mdlid;
759 hdp_chann->mdl = mcap_mdl_ref(mdl);
762 hdp_chann->mdep = app->id;
763 hdp_chann->app = hdp_application_ref(app);
765 hdp_chann->edata = g_new0(struct hdp_echo_data, 1);
767 hdp_chann->path = g_strdup_printf("%s/chan%d",
768 device_get_path(hdp_chann->dev->dev),
771 dev->channels = g_slist_append(dev->channels,
772 hdp_channel_ref(hdp_chann));
774 if (hdp_chann->mdep == HDP_MDEP_ECHO)
775 return hdp_channel_ref(hdp_chann);
777 if (!g_dbus_register_interface(btd_get_dbus_connection(),
778 hdp_chann->path, HEALTH_CHANNEL,
779 health_channels_methods, NULL,
780 health_channels_properties, hdp_chann,
781 health_channel_destroy)) {
782 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
783 "Can't register the channel interface");
784 health_channel_destroy(hdp_chann);
788 return hdp_channel_ref(hdp_chann);
791 static void remove_channels(struct hdp_device *dev)
793 struct hdp_channel *chan;
796 while (dev->channels != NULL) {
797 chan = dev->channels->data;
799 path = g_strdup(chan->path);
800 if (!g_dbus_unregister_interface(btd_get_dbus_connection(),
801 path, HEALTH_CHANNEL))
802 health_channel_destroy(chan);
807 static void close_device_con(struct hdp_device *dev, gboolean cache)
809 if (dev->mcl == NULL)
812 mcap_close_mcl(dev->mcl, cache);
813 dev->mcl_conn = FALSE;
818 device_unref_mcl(dev);
819 remove_channels(dev);
821 if (!dev->sdp_present) {
824 path = device_get_path(dev->dev);
825 g_dbus_unregister_interface(btd_get_dbus_connection(),
826 path, HEALTH_DEVICE);
830 static int send_echo_data(int sock, const void *buf, uint32_t size)
832 const uint8_t *buf_b = buf;
835 while (sent < size) {
836 int n = write(sock, buf_b + sent, size - sent);
845 static gboolean serve_echo(GIOChannel *io_chan, GIOCondition cond,
848 struct hdp_channel *chan = data;
849 uint8_t buf[MCAP_DC_MTU];
852 if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
853 hdp_channel_unref(chan);
857 if (chan->edata->echo_done)
860 chan->edata->echo_done = TRUE;
862 fd = g_io_channel_unix_get_fd(io_chan);
864 len = read(fd, buf, sizeof(buf));
868 if (send_echo_data(fd, buf, len) >= 0)
872 close_device_con(chan->dev, FALSE);
873 hdp_channel_unref(chan);
877 static gboolean check_channel_conf(struct hdp_channel *chan)
885 fd = mcap_mdl_get_fd(chan->mdl);
888 io = g_io_channel_unix_new(fd);
890 if (!bt_io_get(io, &err,
891 BT_IO_OPT_MODE, &mode,
892 BT_IO_OPT_IMTU, &imtu,
893 BT_IO_OPT_OMTU, &omtu,
894 BT_IO_OPT_INVALID)) {
895 error("Error: %s", err->message);
896 g_io_channel_unref(io);
901 g_io_channel_unref(io);
903 switch (chan->config) {
904 case HDP_RELIABLE_DC:
905 if (mode != BT_IO_MODE_ERTM)
908 case HDP_STREAMING_DC:
909 if (mode != BT_IO_MODE_STREAMING)
913 error("Error: Connected with unknown configuration");
917 DBG("MDL imtu %d omtu %d Channel imtu %d omtu %d", imtu, omtu,
918 chan->imtu, chan->omtu);
925 if (chan->imtu != imtu || chan->omtu != omtu)
931 static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
933 struct hdp_device *dev = data;
934 struct hdp_channel *chan;
938 if (dev->ndc == NULL)
942 if (chan->mdl == NULL)
943 chan->mdl = mcap_mdl_ref(mdl);
945 if (g_slist_find(dev->channels, chan) == NULL)
946 dev->channels = g_slist_prepend(dev->channels,
947 hdp_channel_ref(chan));
949 if (!check_channel_conf(chan)) {
954 if (chan->mdep == HDP_MDEP_ECHO) {
958 fd = mcap_mdl_get_fd(chan->mdl);
962 chan->edata->echo_done = FALSE;
963 io = g_io_channel_unix_new(fd);
964 g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
965 serve_echo, hdp_channel_ref(chan));
966 g_io_channel_unref(io);
970 g_dbus_emit_signal(btd_get_dbus_connection(), device_get_path(dev->dev),
971 HEALTH_DEVICE, "ChannelConnected",
972 DBUS_TYPE_OBJECT_PATH, &chan->path,
978 dev->fr = hdp_channel_ref(chan);
980 g_dbus_emit_property_changed(btd_get_dbus_connection(),
981 device_get_path(dev->dev), HEALTH_DEVICE,
985 hdp_channel_unref(dev->ndc);
989 static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
991 /* struct hdp_device *dev = data; */
998 static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
1000 struct hdp_device *dev = data;
1001 struct hdp_channel *chan;
1007 l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1013 path = g_strdup(chan->path);
1014 if (!g_dbus_unregister_interface(btd_get_dbus_connection(),
1015 path, HEALTH_CHANNEL))
1016 health_channel_destroy(chan);
1020 static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
1022 struct hdp_device *dev = data;
1026 if (dev->ndc == NULL)
1029 dev->ndc->mdl = mcap_mdl_ref(mdl);
1031 if (g_slist_find(dev->channels, dev->ndc) == NULL)
1032 dev->channels = g_slist_prepend(dev->channels,
1033 hdp_channel_ref(dev->ndc));
1035 if (dev->ndc->mdep != HDP_MDEP_ECHO)
1036 g_dbus_emit_signal(btd_get_dbus_connection(),
1037 device_get_path(dev->dev),
1038 HEALTH_DEVICE, "ChannelConnected",
1039 DBUS_TYPE_OBJECT_PATH, &dev->ndc->path,
1042 hdp_channel_unref(dev->ndc);
1046 static uint8_t hdp2l2cap_mode(uint8_t hdp_mode)
1048 return hdp_mode == HDP_STREAMING_DC ? BT_IO_MODE_STREAMING :
1052 static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
1053 uint16_t mdlid, uint8_t *conf, void *data)
1055 struct hdp_device *dev = data;
1056 struct hdp_application *app;
1060 DBG("Data channel request");
1062 if (mdepid == HDP_MDEP_ECHO) {
1064 case HDP_NO_PREFERENCE_DC:
1065 *conf = HDP_RELIABLE_DC;
1067 case HDP_RELIABLE_DC:
1069 case HDP_STREAMING_DC:
1070 return MCAP_CONFIGURATION_REJECTED;
1072 /* Special case defined in HDP spec 3.4. When an invalid
1073 * configuration is received we shall close the MCL when
1074 * we are still processing the callback. */
1075 close_device_con(dev, FALSE);
1076 return MCAP_CONFIGURATION_REJECTED; /* not processed */
1079 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1080 BT_IO_MODE_ERTM, &err)) {
1081 error("Error: %s", err->message);
1083 return MCAP_MDL_BUSY;
1086 dev->ndc = create_channel(dev, *conf, NULL, mdlid, NULL, NULL);
1087 if (dev->ndc == NULL)
1088 return MCAP_MDL_BUSY;
1090 return MCAP_SUCCESS;
1093 l = g_slist_find_custom(applications, &mdepid, cmp_app_id);
1095 return MCAP_INVALID_MDEP;
1099 /* Check if is the first dc if so,
1100 * only reliable configuration is allowed */
1102 case HDP_NO_PREFERENCE_DC:
1103 if (app->role == HDP_SINK)
1104 return MCAP_CONFIGURATION_REJECTED;
1105 else if (dev->fr && app->chan_type_set)
1106 *conf = app->chan_type;
1108 *conf = HDP_RELIABLE_DC;
1110 case HDP_STREAMING_DC:
1111 if (!dev->fr || app->role == HDP_SOURCE)
1112 return MCAP_CONFIGURATION_REJECTED;
1114 case HDP_RELIABLE_DC:
1115 if (app->role == HDP_SOURCE)
1116 return MCAP_CONFIGURATION_REJECTED;
1119 /* Special case defined in HDP spec 3.4. When an invalid
1120 * configuration is received we shall close the MCL when
1121 * we are still processing the callback. */
1122 close_device_con(dev, FALSE);
1123 return MCAP_CONFIGURATION_REJECTED; /* not processed */
1126 l = g_slist_find_custom(dev->channels, &mdlid, cmp_chan_mdlid);
1128 struct hdp_channel *chan = l->data;
1131 path = g_strdup(chan->path);
1132 g_dbus_unregister_interface(btd_get_dbus_connection(),
1133 path, HEALTH_CHANNEL);
1137 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1138 hdp2l2cap_mode(*conf), &err)) {
1139 error("Error: %s", err->message);
1141 return MCAP_MDL_BUSY;
1144 dev->ndc = create_channel(dev, *conf, NULL, mdlid, app, NULL);
1145 if (dev->ndc == NULL)
1146 return MCAP_MDL_BUSY;
1148 return MCAP_SUCCESS;
1151 static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
1153 struct hdp_device *dev = data;
1154 struct hdp_channel *chan;
1158 l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1160 return MCAP_INVALID_MDL;
1164 if (dev->fr == NULL && chan->config != HDP_RELIABLE_DC &&
1165 chan->mdep != HDP_MDEP_ECHO)
1166 return MCAP_UNSPECIFIED_ERROR;
1168 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1169 hdp2l2cap_mode(chan->config), &err)) {
1170 error("Error: %s", err->message);
1172 return MCAP_MDL_BUSY;
1175 dev->ndc = hdp_channel_ref(chan);
1177 return MCAP_SUCCESS;
1180 gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err)
1184 if (device->mcl == NULL)
1187 ret = mcap_mcl_set_cb(device->mcl, device, err,
1188 MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
1189 MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
1190 MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
1191 MCAP_MDL_CB_ABORTED, hdp_mcap_mdl_aborted_cb,
1192 MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
1193 MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
1194 MCAP_MDL_CB_INVALID);
1198 error("Can't set mcl callbacks, closing mcl");
1199 close_device_con(device, TRUE);
1204 static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
1206 struct hdp_device *hdp_device;
1210 mcap_mcl_get_addr(mcl, &addr);
1211 l = g_slist_find_custom(devices, &addr, cmp_dev_addr);
1213 struct hdp_adapter *hdp_adapter = data;
1214 struct btd_device *device;
1216 device = btd_adapter_get_device(hdp_adapter->btd_adapter,
1217 &addr, BDADDR_BREDR);
1220 hdp_device = create_health_device(device);
1223 devices = g_slist_append(devices, hdp_device);
1225 hdp_device = l->data;
1227 hdp_device->mcl = mcap_mcl_ref(mcl);
1228 hdp_device->mcl_conn = TRUE;
1230 DBG("New mcl connected from %s", device_get_path(hdp_device->dev));
1232 hdp_set_mcl_cb(hdp_device, NULL);
1235 static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
1237 struct hdp_device *hdp_device;
1240 l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1244 hdp_device = l->data;
1245 hdp_device->mcl_conn = TRUE;
1247 DBG("MCL reconnected %s", device_get_path(hdp_device->dev));
1249 hdp_set_mcl_cb(hdp_device, NULL);
1252 static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
1254 struct hdp_device *hdp_device;
1257 l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1261 hdp_device = l->data;
1262 hdp_device->mcl_conn = FALSE;
1264 DBG("Mcl disconnected %s", device_get_path(hdp_device->dev));
1267 static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
1269 struct hdp_device *hdp_device;
1273 l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1277 hdp_device = l->data;
1278 device_unref_mcl(hdp_device);
1280 if (hdp_device->sdp_present)
1283 /* Because remote device hasn't announced an HDP record */
1284 /* the Bluetooth daemon won't notify when the device shall */
1285 /* be removed. Then we have to remove the HealthDevice */
1286 /* interface manually */
1287 path = device_get_path(hdp_device->dev);
1288 g_dbus_unregister_interface(btd_get_dbus_connection(),
1289 path, HEALTH_DEVICE);
1290 DBG("Mcl uncached %s", path);
1293 static void check_devices_mcl(void)
1295 struct hdp_device *dev;
1296 GSList *l, *to_delete = NULL;
1298 for (l = devices; l; l = l->next) {
1300 device_unref_mcl(dev);
1302 if (!dev->sdp_present)
1303 to_delete = g_slist_append(to_delete, dev);
1305 remove_channels(dev);
1308 for (l = to_delete; l; l = l->next) {
1311 path = device_get_path(dev->dev);
1312 g_dbus_unregister_interface(btd_get_dbus_connection(),
1313 path, HEALTH_DEVICE);
1316 g_slist_free(to_delete);
1319 static void release_adapter_instance(struct hdp_adapter *hdp_adapter)
1321 if (hdp_adapter->mi == NULL)
1324 check_devices_mcl();
1325 mcap_release_instance(hdp_adapter->mi);
1326 mcap_instance_unref(hdp_adapter->mi);
1327 hdp_adapter->mi = NULL;
1330 static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
1333 const bdaddr_t *src;
1335 if (applications == NULL) {
1336 release_adapter_instance(hdp_adapter);
1340 if (hdp_adapter->mi != NULL)
1343 src = btd_adapter_get_address(hdp_adapter->btd_adapter);
1345 hdp_adapter->mi = mcap_create_instance(src,
1346 BT_IO_SEC_MEDIUM, 0, 0,
1347 mcl_connected, mcl_reconnected,
1348 mcl_disconnected, mcl_uncached,
1349 NULL, /* CSP is not used by now */
1351 if (hdp_adapter->mi == NULL) {
1352 error("Error creating the MCAP instance: %s", err->message);
1357 hdp_adapter->ccpsm = mcap_get_ctrl_psm(hdp_adapter->mi, &err);
1359 error("Error getting MCAP control PSM: %s", err->message);
1363 hdp_adapter->dcpsm = mcap_get_data_psm(hdp_adapter->mi, &err);
1365 error("Error getting MCAP data PSM: %s", err->message);
1370 if (hdp_update_sdp_record(hdp_adapter, applications))
1372 error("Error updating the SDP record");
1375 release_adapter_instance(hdp_adapter);
1382 static void update_adapter_cb(void *data, void *user_data)
1384 update_adapter(data);
1387 int hdp_adapter_register(struct btd_adapter *adapter)
1389 struct hdp_adapter *hdp_adapter;
1391 hdp_adapter = g_new0(struct hdp_adapter, 1);
1392 hdp_adapter->btd_adapter = btd_adapter_ref(adapter);
1394 if(!update_adapter(hdp_adapter))
1397 adapters = g_slist_append(adapters, hdp_adapter);
1402 btd_adapter_unref(hdp_adapter->btd_adapter);
1403 g_free(hdp_adapter);
1407 void hdp_adapter_unregister(struct btd_adapter *adapter)
1409 struct hdp_adapter *hdp_adapter;
1412 l = g_slist_find_custom(adapters, adapter, cmp_adapter);
1417 hdp_adapter = l->data;
1418 adapters = g_slist_remove(adapters, hdp_adapter);
1419 if (hdp_adapter->sdp_handler > 0)
1420 adapter_service_remove(adapter, hdp_adapter->sdp_handler);
1421 release_adapter_instance(hdp_adapter);
1422 btd_adapter_unref(hdp_adapter->btd_adapter);
1423 g_free(hdp_adapter);
1426 static void delete_echo_channel_cb(GError *err, gpointer chan)
1428 if (err != NULL && err->code != MCAP_INVALID_MDL) {
1429 /* TODO: Decide if more action is required here */
1430 error("Error deleting echo channel: %s", err->message);
1434 health_channel_destroy(chan);
1437 static void delete_echo_channel(struct hdp_channel *chan)
1441 if (!chan->dev->mcl_conn) {
1442 error("Echo channel cannot be deleted: mcl closed");
1446 if (mcap_delete_mdl(chan->mdl, delete_echo_channel_cb,
1447 hdp_channel_ref(chan),
1448 (GDestroyNotify) hdp_channel_unref, &err))
1451 hdp_channel_unref(chan);
1452 error("Error deleting the echo channel: %s", err->message);
1455 /* TODO: Decide if more action is required here */
1458 static void abort_echo_channel_cb(GError *err, gpointer data)
1460 struct hdp_channel *chan = data;
1462 if (err != NULL && err->code != MCAP_ERROR_INVALID_OPERATION) {
1463 error("Aborting error: %s", err->message);
1464 if (err->code == MCAP_INVALID_MDL) {
1465 /* MDL is removed from MCAP so we can */
1466 /* free the data channel without sending */
1467 /* a MD_DELETE_MDL_REQ */
1468 /* TODO review the above comment */
1469 /* hdp_channel_unref(chan); */
1474 delete_echo_channel(chan);
1477 static void destroy_create_dc_data(gpointer data)
1479 struct hdp_create_dc *dc_data = data;
1481 hdp_create_data_unref(dc_data);
1484 static void *generate_echo_packet(void)
1488 buf = g_malloc(HDP_ECHO_LEN);
1492 if (getrandom(buf, HDP_ECHO_LEN, 0) < 0) {
1500 static gboolean check_echo(GIOChannel *io_chan, GIOCondition cond,
1503 struct hdp_tmp_dc_data *hdp_conn = data;
1504 struct hdp_echo_data *edata = hdp_conn->hdp_chann->edata;
1505 struct hdp_channel *chan = hdp_conn->hdp_chann;
1506 uint8_t buf[MCAP_DC_MTU];
1511 if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
1516 fd = g_io_channel_unix_get_fd(io_chan);
1518 len = read(fd, buf, sizeof(buf));
1519 if (len != HDP_ECHO_LEN) {
1524 value = (memcmp(buf, edata->buf, len) == 0);
1527 reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_BOOLEAN, &value,
1529 g_dbus_send_message(btd_get_dbus_connection(), reply);
1530 timeout_remove(edata->tid);
1536 close_device_con(chan->dev, FALSE);
1538 delete_echo_channel(chan);
1539 hdp_tmp_dc_data_unref(hdp_conn);
1544 static bool echo_timeout(gpointer data)
1546 struct hdp_channel *chan = data;
1550 error("Error: Echo request timeout");
1551 chan->edata->tid = 0;
1553 fd = mcap_mdl_get_fd(chan->mdl);
1557 io = g_io_channel_unix_new(fd);
1558 g_io_channel_shutdown(io, TRUE, NULL);
1563 static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
1566 DBusConnection *conn = btd_get_dbus_connection();
1567 struct hdp_tmp_dc_data *hdp_conn = data;
1568 struct hdp_echo_data *edata;
1569 GError *gerr = NULL;
1575 reply = g_dbus_create_error(hdp_conn->msg,
1576 ERROR_INTERFACE ".HealthError",
1577 "%s", err->message);
1578 g_dbus_send_message(conn, reply);
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,
1587 error("%s", gerr->message);
1589 hdp_channel_unref(hdp_conn->hdp_chann);
1594 fd = mcap_mdl_get_fd(hdp_conn->hdp_chann->mdl);
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(conn, reply);
1600 delete_echo_channel(hdp_conn->hdp_chann);
1604 edata = hdp_conn->hdp_chann->edata;
1605 edata->buf = generate_echo_packet();
1606 send_echo_data(fd, edata->buf, HDP_ECHO_LEN);
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));
1612 edata->tid = timeout_add_seconds(ECHO_TIMEOUT, echo_timeout,
1613 hdp_channel_ref(hdp_conn->hdp_chann),
1614 (timeout_destroy_func_t) hdp_channel_unref);
1616 g_io_channel_unref(io);
1619 static void delete_mdl_cb(GError *err, gpointer data)
1622 error("Deleting error: %s", err->message);
1625 static void abort_and_del_mdl_cb(GError *err, gpointer data)
1627 struct mcap_mdl *mdl = data;
1628 GError *gerr = NULL;
1631 error("%s", err->message);
1632 if (err->code == MCAP_INVALID_MDL) {
1633 /* MDL is removed from MCAP so we don't */
1634 /* need to delete it. */
1639 if (!mcap_delete_mdl(mdl, delete_mdl_cb, NULL, NULL, &gerr)) {
1640 error("%s", gerr->message);
1645 static void abort_mdl_connection_cb(GError *err, gpointer data)
1647 struct hdp_tmp_dc_data *hdp_conn = data;
1648 struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1651 error("Aborting error: %s", err->message);
1653 /* Connection operation has failed but we have to */
1654 /* notify the channel created at MCAP level */
1655 if (hdp_chann->mdep != HDP_MDEP_ECHO)
1656 g_dbus_emit_signal(btd_get_dbus_connection(),
1657 device_get_path(hdp_chann->dev->dev),
1658 HEALTH_DEVICE, "ChannelConnected",
1659 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1663 static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
1665 DBusConnection *conn = btd_get_dbus_connection();
1666 struct hdp_tmp_dc_data *hdp_conn = data;
1667 struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1668 struct hdp_device *dev = hdp_chann->dev;
1670 GError *gerr = NULL;
1673 error("%s", err->message);
1674 reply = g_dbus_create_reply(hdp_conn->msg,
1675 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1677 g_dbus_send_message(conn, reply);
1679 /* Send abort request because remote side */
1680 /* is now in PENDING state */
1681 if (!mcap_mdl_abort(hdp_chann->mdl, abort_mdl_connection_cb,
1682 hdp_tmp_dc_data_ref(hdp_conn),
1683 hdp_tmp_dc_data_destroy, &gerr)) {
1684 hdp_tmp_dc_data_unref(hdp_conn);
1685 error("%s", gerr->message);
1691 reply = g_dbus_create_reply(hdp_conn->msg,
1692 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1694 g_dbus_send_message(conn, reply);
1696 g_dbus_emit_signal(conn, device_get_path(hdp_chann->dev->dev),
1697 HEALTH_DEVICE, "ChannelConnected",
1698 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1701 if (!check_channel_conf(hdp_chann)) {
1702 close_mdl(hdp_chann);
1706 if (dev->fr != NULL)
1709 dev->fr = hdp_channel_ref(hdp_chann);
1711 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1712 device_get_path(dev->dev), HEALTH_DEVICE,
1716 static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
1717 GError *err, gpointer data)
1719 DBusConnection *conn = btd_get_dbus_connection();
1720 struct hdp_create_dc *user_data = data;
1721 struct hdp_tmp_dc_data *hdp_conn;
1722 struct hdp_channel *hdp_chan;
1723 GError *gerr = NULL;
1727 reply = g_dbus_create_error(user_data->msg,
1728 ERROR_INTERFACE ".HealthError",
1729 "%s", err->message);
1730 g_dbus_send_message(conn, reply);
1734 if (user_data->mdep != HDP_MDEP_ECHO &&
1735 user_data->config == HDP_NO_PREFERENCE_DC) {
1736 if (user_data->dev->fr == NULL && conf != HDP_RELIABLE_DC) {
1737 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1738 "Data channel aborted, first data "
1739 "channel should be reliable");
1741 } else if (conf == HDP_NO_PREFERENCE_DC ||
1742 conf > HDP_STREAMING_DC) {
1743 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1744 "Data channel aborted, "
1745 "configuration error");
1750 hdp_chan = create_channel(user_data->dev, conf, mdl,
1751 mcap_mdl_get_mdlid(mdl),
1752 user_data->app, &gerr);
1753 if (hdp_chan == NULL)
1756 hdp_conn = g_new0(struct hdp_tmp_dc_data, 1);
1757 hdp_conn->msg = dbus_message_ref(user_data->msg);
1758 hdp_conn->hdp_chann = hdp_chan;
1759 hdp_conn->cb = user_data->cb;
1760 hdp_chan->mdep = user_data->mdep;
1762 if (hdp_get_dcpsm(hdp_chan->dev, hdp_get_dcpsm_cb,
1763 hdp_tmp_dc_data_ref(hdp_conn),
1764 hdp_tmp_dc_data_destroy, &gerr))
1767 error("%s", gerr->message);
1770 reply = g_dbus_create_reply(hdp_conn->msg,
1771 DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
1773 g_dbus_send_message(conn, reply);
1774 hdp_tmp_dc_data_unref(hdp_conn);
1776 /* Send abort request because remote side is now in PENDING state */
1777 if (!mcap_mdl_abort(hdp_chan->mdl, abort_mdl_connection_cb,
1778 hdp_tmp_dc_data_ref(hdp_conn),
1779 hdp_tmp_dc_data_destroy, &gerr)) {
1780 hdp_tmp_dc_data_unref(hdp_conn);
1781 error("%s", gerr->message);
1788 reply = g_dbus_create_error(user_data->msg,
1789 ERROR_INTERFACE ".HealthError",
1790 "%s", gerr->message);
1791 g_dbus_send_message(conn, reply);
1794 /* Send abort request because remote side is now in PENDING */
1795 /* state. Then we have to delete it because we couldn't */
1796 /* register the HealthChannel interface */
1797 if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl),
1798 (GDestroyNotify) mcap_mdl_unref, &gerr)) {
1799 error("%s", gerr->message);
1801 mcap_mdl_unref(mdl);
1805 static void device_create_dc_cb(gpointer user_data, GError *err)
1807 DBusConnection *conn = btd_get_dbus_connection();
1808 struct hdp_create_dc *data = user_data;
1810 GError *gerr = NULL;
1813 reply = g_dbus_create_error(data->msg,
1814 ERROR_INTERFACE ".HealthError",
1815 "%s", err->message);
1816 g_dbus_send_message(conn, reply);
1820 if (data->dev->mcl == NULL) {
1821 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1826 hdp_create_data_ref(data);
1828 if (mcap_create_mdl(data->dev->mcl, data->mdep, data->config,
1829 device_create_mdl_cb, data,
1830 destroy_create_dc_data, &gerr))
1832 hdp_create_data_unref(data);
1835 reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
1836 "%s", gerr->message);
1838 g_dbus_send_message(conn, reply);
1841 static DBusMessage *device_echo(DBusConnection *conn,
1842 DBusMessage *msg, void *user_data)
1844 struct hdp_device *device = user_data;
1845 struct hdp_create_dc *data;
1849 data = g_new0(struct hdp_create_dc, 1);
1850 data->dev = health_device_ref(device);
1851 data->mdep = HDP_MDEP_ECHO;
1852 data->config = HDP_RELIABLE_DC;
1853 data->msg = dbus_message_ref(msg);
1854 data->cb = hdp_echo_connect_cb;
1855 hdp_create_data_ref(data);
1857 if (device->mcl_conn && device->mcl) {
1858 if (mcap_create_mdl(device->mcl, data->mdep, data->config,
1859 device_create_mdl_cb, data,
1860 destroy_create_dc_data, &err))
1865 if (hdp_establish_mcl(data->dev, device_create_dc_cb,
1866 data, destroy_create_dc_data, &err))
1870 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1871 "%s", err->message);
1873 hdp_create_data_unref(data);
1877 static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
1879 DBusConnection *conn = btd_get_dbus_connection();
1880 struct hdp_create_dc *dc_data, *user_data = data;
1882 GError *gerr = NULL;
1885 reply = g_dbus_create_error(user_data->msg,
1886 ERROR_INTERFACE ".HealthError",
1887 "%s", err->message);
1888 g_dbus_send_message(conn, reply);
1892 dc_data = hdp_create_data_ref(user_data);
1893 dc_data->mdep = mdep;
1895 if (user_data->dev->mcl_conn) {
1896 device_create_dc_cb(dc_data, NULL);
1897 hdp_create_data_unref(dc_data);
1901 if (hdp_establish_mcl(dc_data->dev, device_create_dc_cb,
1902 dc_data, destroy_create_dc_data, &gerr))
1905 reply = g_dbus_create_error(user_data->msg,
1906 ERROR_INTERFACE ".HealthError",
1907 "%s", gerr->message);
1908 hdp_create_data_unref(dc_data);
1910 g_dbus_send_message(conn, reply);
1913 static DBusMessage *device_create_channel(DBusConnection *conn,
1914 DBusMessage *msg, void *user_data)
1916 struct hdp_device *device = user_data;
1917 struct hdp_application *app;
1918 struct hdp_create_dc *data;
1919 char *app_path, *conf;
1925 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &app_path,
1926 DBUS_TYPE_STRING, &conf,
1928 return btd_error_invalid_args(msg);
1930 l = g_slist_find_custom(applications, app_path, cmp_app);
1932 return btd_error_invalid_args(msg);
1936 if (g_ascii_strcasecmp("reliable", conf) == 0)
1937 config = HDP_RELIABLE_DC;
1938 else if (g_ascii_strcasecmp("streaming", conf) == 0)
1939 config = HDP_STREAMING_DC;
1940 else if (g_ascii_strcasecmp("any", conf) == 0)
1941 config = HDP_NO_PREFERENCE_DC;
1943 return btd_error_invalid_args(msg);
1945 if (app->role == HDP_SINK && config != HDP_NO_PREFERENCE_DC)
1946 return btd_error_invalid_args(msg);
1948 if (app->role == HDP_SOURCE && config == HDP_NO_PREFERENCE_DC)
1949 return btd_error_invalid_args(msg);
1951 if (!device->fr && config == HDP_STREAMING_DC)
1952 return btd_error_invalid_args(msg);
1954 data = g_new0(struct hdp_create_dc, 1);
1955 data->dev = health_device_ref(device);
1956 data->config = config;
1957 data->app = hdp_application_ref(app);
1958 data->msg = dbus_message_ref(msg);
1959 data->cb = hdp_mdl_conn_cb;
1961 if (hdp_get_mdep(device, l->data, device_get_mdep_cb,
1962 hdp_create_data_ref(data),
1963 destroy_create_dc_data, &err))
1966 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1967 "%s", err->message);
1969 hdp_create_data_unref(data);
1973 static void hdp_mdl_delete_cb(GError *err, gpointer data)
1975 DBusConnection *conn = btd_get_dbus_connection();
1976 struct hdp_tmp_dc_data *del_data = data;
1980 if (err != NULL && err->code != MCAP_INVALID_MDL) {
1981 reply = g_dbus_create_error(del_data->msg,
1982 ERROR_INTERFACE ".HealthError",
1983 "%s", err->message);
1984 g_dbus_send_message(conn, reply);
1988 path = g_strdup(del_data->hdp_chann->path);
1989 g_dbus_unregister_interface(conn, path, HEALTH_CHANNEL);
1992 reply = g_dbus_create_reply(del_data->msg, DBUS_TYPE_INVALID);
1993 g_dbus_send_message(conn, reply);
1996 static void hdp_continue_del_cb(gpointer user_data, GError *err)
1998 DBusConnection *conn = btd_get_dbus_connection();
1999 struct hdp_tmp_dc_data *del_data = user_data;
2000 GError *gerr = NULL;
2004 reply = g_dbus_create_error(del_data->msg,
2005 ERROR_INTERFACE ".HealthError",
2006 "%s", err->message);
2007 g_dbus_send_message(conn, reply);
2011 if (mcap_delete_mdl(del_data->hdp_chann->mdl, hdp_mdl_delete_cb,
2012 hdp_tmp_dc_data_ref(del_data),
2013 hdp_tmp_dc_data_destroy, &gerr))
2016 reply = g_dbus_create_error(del_data->msg,
2017 ERROR_INTERFACE ".HealthError",
2018 "%s", gerr->message);
2019 hdp_tmp_dc_data_unref(del_data);
2021 g_dbus_send_message(conn, reply);
2024 static DBusMessage *device_destroy_channel(DBusConnection *conn,
2025 DBusMessage *msg, void *user_data)
2027 struct hdp_device *device = user_data;
2028 struct hdp_tmp_dc_data *del_data;
2029 struct hdp_channel *hdp_chan;
2035 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
2036 DBUS_TYPE_INVALID)){
2037 return btd_error_invalid_args(msg);
2040 l = g_slist_find_custom(device->channels, path, cmp_chan_path);
2042 return btd_error_invalid_args(msg);
2045 del_data = g_new0(struct hdp_tmp_dc_data, 1);
2046 del_data->msg = dbus_message_ref(msg);
2047 del_data->hdp_chann = hdp_channel_ref(hdp_chan);
2049 if (device->mcl_conn) {
2050 if (mcap_delete_mdl(hdp_chan->mdl, hdp_mdl_delete_cb,
2051 hdp_tmp_dc_data_ref(del_data),
2052 hdp_tmp_dc_data_destroy, &err))
2057 if (hdp_establish_mcl(device, hdp_continue_del_cb,
2058 hdp_tmp_dc_data_ref(del_data),
2059 hdp_tmp_dc_data_destroy, &err))
2063 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
2064 "%s", err->message);
2065 hdp_tmp_dc_data_unref(del_data);
2070 static gboolean dev_property_exists_main_channel(
2071 const GDBusPropertyTable *property, void *data)
2073 struct hdp_device *device = data;
2074 return device->fr != NULL;
2077 static gboolean dev_property_get_main_channel(
2078 const GDBusPropertyTable *property,
2079 DBusMessageIter *iter, void *data)
2081 struct hdp_device *device = data;
2083 if (device->fr == NULL)
2086 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2092 static void health_device_destroy(void *data)
2094 struct hdp_device *device = data;
2096 DBG("Unregistered interface %s on path %s", HEALTH_DEVICE,
2097 device_get_path(device->dev));
2099 remove_channels(device);
2100 if (device->ndc != NULL) {
2101 hdp_channel_unref(device->ndc);
2105 devices = g_slist_remove(devices, device);
2106 health_device_unref(device);
2109 static const GDBusMethodTable health_device_methods[] = {
2110 { GDBUS_ASYNC_METHOD("Echo",
2111 NULL, GDBUS_ARGS({ "value", "b" }), device_echo) },
2112 { GDBUS_ASYNC_METHOD("CreateChannel",
2113 GDBUS_ARGS({ "application", "o" },
2114 { "configuration", "s" }),
2115 GDBUS_ARGS({ "channel", "o" }),
2116 device_create_channel) },
2117 { GDBUS_ASYNC_METHOD("DestroyChannel",
2118 GDBUS_ARGS({ "channel", "o" }), NULL,
2119 device_destroy_channel) },
2123 static const GDBusSignalTable health_device_signals[] = {
2124 { GDBUS_SIGNAL("ChannelConnected",
2125 GDBUS_ARGS({ "channel", "o" })) },
2126 { GDBUS_SIGNAL("ChannelDeleted",
2127 GDBUS_ARGS({ "channel", "o" })) },
2131 static const GDBusPropertyTable health_device_properties[] = {
2132 { "MainChannel", "o", dev_property_get_main_channel, NULL,
2133 dev_property_exists_main_channel },
2137 static struct hdp_device *create_health_device(struct btd_device *device)
2139 struct btd_adapter *adapter = device_get_adapter(device);
2140 const char *path = device_get_path(device);
2141 struct hdp_device *dev;
2147 dev = g_new0(struct hdp_device, 1);
2148 dev->dev = btd_device_ref(device);
2149 health_device_ref(dev);
2151 l = g_slist_find_custom(adapters, adapter, cmp_adapter);
2155 dev->hdp_adapter = l->data;
2157 if (!g_dbus_register_interface(btd_get_dbus_connection(),
2158 path, HEALTH_DEVICE,
2159 health_device_methods,
2160 health_device_signals,
2161 health_device_properties,
2162 dev, health_device_destroy)) {
2163 error("D-Bus failed to register %s interface", HEALTH_DEVICE);
2167 DBG("Registered interface %s on path %s", HEALTH_DEVICE, path);
2171 health_device_unref(dev);
2175 int hdp_device_register(struct btd_device *device)
2177 struct hdp_device *hdev;
2180 l = g_slist_find_custom(devices, device, cmp_device);
2183 hdev->sdp_present = TRUE;
2187 hdev = create_health_device(device);
2191 hdev->sdp_present = TRUE;
2193 devices = g_slist_prepend(devices, hdev);
2197 void hdp_device_unregister(struct btd_device *device)
2199 struct hdp_device *hdp_dev;
2203 l = g_slist_find_custom(devices, device, cmp_device);
2208 path = device_get_path(hdp_dev->dev);
2209 g_dbus_unregister_interface(btd_get_dbus_connection(),
2210 path, HEALTH_DEVICE);
2213 int hdp_manager_start(void)
2215 DBG("Starting Health manager");
2217 if (!g_dbus_register_interface(btd_get_dbus_connection(),
2218 MANAGER_PATH, HEALTH_MANAGER,
2219 health_manager_methods, NULL, NULL,
2220 NULL, manager_path_unregister)) {
2221 error("D-Bus failed to register %s interface", HEALTH_MANAGER);
2228 void hdp_manager_stop(void)
2230 g_dbus_unregister_interface(btd_get_dbus_connection(),
2231 MANAGER_PATH, HEALTH_MANAGER);
2233 DBG("Stopped Health manager");
2236 struct hdp_device *health_device_ref(struct hdp_device *hdp_dev)
2240 DBG("(%p): ref=%d", hdp_dev, hdp_dev->ref);
2245 void health_device_unref(struct hdp_device *hdp_dev)
2249 DBG("(%p): ref=%d", hdp_dev, hdp_dev->ref);
2251 if (hdp_dev->ref > 0)
2254 free_health_device(hdp_dev);