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.
21 #include "lib/bluetooth.h"
22 #include "lib/l2cap.h"
25 #include "gdbus/gdbus.h"
27 #include "src/dbus-common.h"
29 #include "src/error.h"
30 #include "src/adapter.h"
31 #include "src/device.h"
33 #include "src/shared/timeout.h"
34 #include "btio/btio.h"
36 #include "hdp_types.h"
41 #define ECHO_TIMEOUT 1 /* second */
42 #define HDP_ECHO_LEN 15
44 static GSList *applications = NULL;
45 static GSList *devices = NULL;
46 static uint8_t next_app_id = HDP_MDEP_INITIAL;
48 static GSList *adapters;
50 static struct hdp_device *create_health_device(struct btd_device *device);
51 static void free_echo_data(struct hdp_echo_data *edata);
53 struct hdp_create_dc {
55 struct hdp_application *app;
56 struct hdp_device *dev;
60 mcap_mdl_operation_cb cb;
63 struct hdp_tmp_dc_data {
65 struct hdp_channel *hdp_chann;
67 mcap_mdl_operation_cb cb;
70 struct hdp_echo_data {
71 gboolean echo_done; /* Is a echo was already done */
72 gpointer buf; /* echo packet sent */
73 unsigned int tid; /* echo timeout */
76 static struct hdp_channel *hdp_channel_ref(struct hdp_channel *chan)
83 DBG("(%p): ref=%d", chan, chan->ref);
87 static void free_health_channel(struct hdp_channel *chan)
89 if (chan->mdep == HDP_MDEP_ECHO) {
90 free_echo_data(chan->edata);
94 mcap_mdl_unref(chan->mdl);
95 hdp_application_unref(chan->app);
96 health_device_unref(chan->dev);
101 static void hdp_channel_unref(struct hdp_channel *chan)
107 DBG("(%p): ref=%d", chan, chan->ref);
112 free_health_channel(chan);
115 static void free_hdp_create_dc(struct hdp_create_dc *dc_data)
117 dbus_message_unref(dc_data->msg);
118 hdp_application_unref(dc_data->app);
119 health_device_unref(dc_data->dev);
124 static struct hdp_create_dc *hdp_create_data_ref(struct hdp_create_dc *dc_data)
128 DBG("(%p): ref=%d", dc_data, dc_data->ref);
133 static void hdp_create_data_unref(struct hdp_create_dc *dc_data)
137 DBG("(%p): ref=%d", dc_data, dc_data->ref);
139 if (dc_data->ref > 0)
142 free_hdp_create_dc(dc_data);
145 static void free_hdp_conn_dc(struct hdp_tmp_dc_data *data)
147 dbus_message_unref(data->msg);
148 hdp_channel_unref(data->hdp_chann);
153 static struct hdp_tmp_dc_data *hdp_tmp_dc_data_ref(struct hdp_tmp_dc_data *data)
157 DBG("hdp_conn_data_ref(%p): ref=%d", data, data->ref);
162 static void hdp_tmp_dc_data_unref(struct hdp_tmp_dc_data *data)
166 DBG("hdp_conn_data_unref(%p): ref=%d", data, data->ref);
171 free_hdp_conn_dc(data);
174 static int cmp_app_id(gconstpointer a, gconstpointer b)
176 const struct hdp_application *app = a;
177 const uint8_t *id = b;
179 return app->id - *id;
182 static int cmp_adapter(gconstpointer a, gconstpointer b)
184 const struct hdp_adapter *hdp_adapter = a;
185 const struct btd_adapter *adapter = b;
187 if (hdp_adapter->btd_adapter == adapter)
193 static int cmp_device(gconstpointer a, gconstpointer b)
195 const struct hdp_device *hdp_device = a;
196 const struct btd_device *device = b;
198 if (hdp_device->dev == device)
204 static int cmp_dev_addr(gconstpointer a, gconstpointer dst)
206 const struct hdp_device *device = a;
208 return bacmp(device_get_address(device->dev), dst);
211 static int cmp_dev_mcl(gconstpointer a, gconstpointer mcl)
213 const struct hdp_device *device = a;
215 if (mcl == device->mcl)
220 static int cmp_chan_mdlid(gconstpointer a, gconstpointer b)
222 const struct hdp_channel *chan = a;
223 const uint16_t *mdlid = b;
225 return chan->mdlid - *mdlid;
228 static int cmp_chan_path(gconstpointer a, gconstpointer b)
230 const struct hdp_channel *chan = a;
231 const char *path = b;
233 return g_ascii_strcasecmp(chan->path, path);
236 static int cmp_chan_mdl(gconstpointer a, gconstpointer mdl)
238 const struct hdp_channel *chan = a;
240 if (chan->mdl == mdl)
245 static uint8_t get_app_id(void)
247 uint8_t id = next_app_id;
250 GSList *l = g_slist_find_custom(applications, &id, cmp_app_id);
253 next_app_id = (id % HDP_MDEP_FINAL) + 1;
256 id = (id % HDP_MDEP_FINAL) + 1;
257 } while (id != next_app_id);
259 /* No more ids available */
263 static int cmp_app(gconstpointer a, gconstpointer b)
265 const struct hdp_application *app = a;
267 return g_strcmp0(app->path, b);
270 static gboolean set_app_path(struct hdp_application *app)
272 app->id = get_app_id();
275 app->path = g_strdup_printf(MANAGER_PATH "/health_app_%d", app->id);
280 static void device_unref_mcl(struct hdp_device *hdp_device)
282 if (hdp_device->mcl == NULL)
285 mcap_close_mcl(hdp_device->mcl, FALSE);
286 mcap_mcl_unref(hdp_device->mcl);
287 hdp_device->mcl = NULL;
288 hdp_device->mcl_conn = FALSE;
291 static void free_health_device(struct hdp_device *device)
293 if (device->dev != NULL) {
294 btd_device_unref(device->dev);
298 device_unref_mcl(device);
303 static void update_adapter_cb(void *data, void *user_data);
305 static void remove_application(struct hdp_application *app)
307 DBG("Application %s deleted", app->path);
308 hdp_application_unref(app);
310 g_slist_foreach(adapters, update_adapter_cb, NULL);
313 static void client_disconnected(DBusConnection *conn, void *user_data)
315 struct hdp_application *app = user_data;
317 DBG("Client disconnected from the bus, deleting hdp application");
318 applications = g_slist_remove(applications, app);
320 app->dbus_watcher = 0; /* Watcher shouldn't be freed in this case */
321 remove_application(app);
324 static DBusMessage *manager_create_application(DBusConnection *conn,
325 DBusMessage *msg, void *user_data)
327 struct hdp_application *app;
329 DBusMessageIter iter;
332 dbus_message_iter_init(msg, &iter);
333 app = hdp_get_app_config(&iter, &err);
336 return btd_error_invalid_args(msg);
339 name = dbus_message_get_sender(msg);
341 hdp_application_unref(app);
342 return g_dbus_create_error(msg,
343 ERROR_INTERFACE ".HealthError",
344 "Can't get sender name");
347 if (!set_app_path(app)) {
348 hdp_application_unref(app);
349 return g_dbus_create_error(msg,
350 ERROR_INTERFACE ".HealthError",
351 "Can't get a valid id for the application");
354 app->oname = g_strdup(name);
356 applications = g_slist_prepend(applications, app);
359 g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
360 name, client_disconnected, app, NULL);
361 g_slist_foreach(adapters, update_adapter_cb, NULL);
363 DBG("Health application created with id %s", app->path);
365 return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &app->path,
369 static DBusMessage *manager_destroy_application(DBusConnection *conn,
370 DBusMessage *msg, void *user_data)
373 struct hdp_application *app;
376 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
378 return btd_error_invalid_args(msg);
380 l = g_slist_find_custom(applications, path, cmp_app);
383 return g_dbus_create_error(msg,
384 ERROR_INTERFACE ".InvalidArguments",
385 "Invalid arguments in method call, "
386 "no such application");
389 applications = g_slist_remove(applications, app);
391 remove_application(app);
393 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
396 static void application_unref(void *data, void *user_data)
398 hdp_application_unref(data);
401 static void manager_path_unregister(gpointer data)
403 g_slist_foreach(applications, application_unref, NULL);
405 g_slist_free(applications);
408 g_slist_foreach(adapters, update_adapter_cb, NULL);
411 static const GDBusMethodTable health_manager_methods[] = {
412 { GDBUS_METHOD("CreateApplication",
413 GDBUS_ARGS({ "config", "a{sv}" }),
414 GDBUS_ARGS({ "application", "o" }),
415 manager_create_application) },
416 { GDBUS_METHOD("DestroyApplication",
417 GDBUS_ARGS({ "application", "o" }), NULL,
418 manager_destroy_application) },
422 static gboolean channel_property_get_device(const GDBusPropertyTable *property,
423 DBusMessageIter *iter, void *data)
425 struct hdp_channel *chan = data;
426 const char *path = device_get_path(chan->dev->dev);
428 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
433 static gboolean channel_property_get_application(
434 const GDBusPropertyTable *property,
435 DBusMessageIter *iter, void *data)
437 struct hdp_channel *chan = data;
438 const char *path = chan->app->path;
440 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
445 static gboolean channel_property_get_type(const GDBusPropertyTable *property,
446 DBusMessageIter *iter, void *data)
448 struct hdp_channel *chan = data;
451 if (chan->config == HDP_RELIABLE_DC)
456 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &type);
461 static void hdp_tmp_dc_data_destroy(gpointer data)
463 struct hdp_tmp_dc_data *hdp_conn = data;
465 hdp_tmp_dc_data_unref(hdp_conn);
468 static void abort_mdl_cb(GError *err, gpointer data)
471 error("Aborting error: %s", err->message);
474 static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
476 DBusConnection *conn = btd_get_dbus_connection();
477 struct hdp_tmp_dc_data *dc_data = data;
482 struct hdp_channel *chan = dc_data->hdp_chann;
485 error("%s", err->message);
486 reply = g_dbus_create_error(dc_data->msg,
487 ERROR_INTERFACE ".HealthError",
488 "Cannot reconnect: %s", err->message);
489 g_dbus_send_message(conn, reply);
491 /* Send abort request because remote side */
492 /* is now in PENDING state */
493 if (!mcap_mdl_abort(chan->mdl, abort_mdl_cb, NULL, NULL,
495 error("%s", gerr->message);
501 fd = mcap_mdl_get_fd(dc_data->hdp_chann->mdl);
503 reply = g_dbus_create_error(dc_data->msg,
504 ERROR_INTERFACE ".HealthError",
505 "Cannot get file descriptor");
506 g_dbus_send_message(conn, reply);
510 reply = g_dbus_create_reply(dc_data->msg, DBUS_TYPE_UNIX_FD,
511 &fd, DBUS_TYPE_INVALID);
512 g_dbus_send_message(conn, reply);
514 g_dbus_emit_signal(conn, device_get_path(dc_data->hdp_chann->dev->dev),
515 HEALTH_DEVICE, "ChannelConnected",
516 DBUS_TYPE_OBJECT_PATH, &dc_data->hdp_chann->path,
520 static void hdp_get_dcpsm_cb(uint16_t dcpsm, gpointer user_data, GError *err)
522 struct hdp_tmp_dc_data *hdp_conn = user_data;
523 struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
528 hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
532 if (hdp_chann->config == HDP_RELIABLE_DC)
533 mode = BT_IO_MODE_ERTM;
535 mode = BT_IO_MODE_STREAMING;
537 if (mcap_connect_mdl(hdp_chann->mdl, mode, dcpsm, hdp_conn->cb,
538 hdp_tmp_dc_data_ref(hdp_conn),
539 hdp_tmp_dc_data_destroy, &gerr))
542 hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
544 hdp_tmp_dc_data_unref(hdp_conn);
547 static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
550 DBusConnection *conn = btd_get_dbus_connection();
551 struct hdp_tmp_dc_data *dc_data = data;
556 reply = g_dbus_create_error(dc_data->msg,
557 ERROR_INTERFACE ".HealthError",
558 "Cannot reconnect: %s", err->message);
559 g_dbus_send_message(conn, reply);
563 dc_data->cb = hdp_mdl_reconn_cb;
565 if (hdp_get_dcpsm(dc_data->hdp_chann->dev, hdp_get_dcpsm_cb,
566 hdp_tmp_dc_data_ref(dc_data),
567 hdp_tmp_dc_data_destroy, &gerr))
570 error("%s", gerr->message);
572 reply = g_dbus_create_error(dc_data->msg,
573 ERROR_INTERFACE ".HealthError",
574 "Cannot reconnect: %s", gerr->message);
575 g_dbus_send_message(conn, reply);
576 hdp_tmp_dc_data_unref(dc_data);
579 /* Send abort request because remote side is now in PENDING state */
580 if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) {
581 error("%s", gerr->message);
586 static DBusMessage *channel_acquire_continue(struct hdp_tmp_dc_data *data,
594 return g_dbus_create_error(data->msg,
595 ERROR_INTERFACE ".HealthError",
599 fd = mcap_mdl_get_fd(data->hdp_chann->mdl);
601 return g_dbus_create_reply(data->msg, DBUS_TYPE_UNIX_FD, &fd,
604 hdp_tmp_dc_data_ref(data);
605 if (mcap_reconnect_mdl(data->hdp_chann->mdl, device_reconnect_mdl_cb,
606 data, hdp_tmp_dc_data_destroy, &gerr))
609 reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
610 "Cannot reconnect: %s", gerr->message);
612 hdp_tmp_dc_data_unref(data);
617 static void channel_acquire_cb(gpointer data, GError *err)
621 reply = channel_acquire_continue(data, err);
624 g_dbus_send_message(btd_get_dbus_connection(), reply);
627 static DBusMessage *channel_acquire(DBusConnection *conn,
628 DBusMessage *msg, void *user_data)
630 struct hdp_channel *chan = user_data;
631 struct hdp_tmp_dc_data *dc_data;
635 dc_data = g_new0(struct hdp_tmp_dc_data, 1);
636 dc_data->msg = dbus_message_ref(msg);
637 dc_data->hdp_chann = hdp_channel_ref(chan);
639 if (chan->dev->mcl_conn) {
640 reply = channel_acquire_continue(hdp_tmp_dc_data_ref(dc_data),
642 hdp_tmp_dc_data_unref(dc_data);
646 if (hdp_establish_mcl(chan->dev, channel_acquire_cb,
647 hdp_tmp_dc_data_ref(dc_data),
648 hdp_tmp_dc_data_destroy, &gerr))
651 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
652 "%s", gerr->message);
653 hdp_tmp_dc_data_unref(dc_data);
659 static void close_mdl(struct hdp_channel *hdp_chann)
663 fd = mcap_mdl_get_fd(hdp_chann->mdl);
670 static DBusMessage *channel_release(DBusConnection *conn,
671 DBusMessage *msg, void *user_data)
673 struct hdp_channel *hdp_chann = user_data;
675 close_mdl(hdp_chann);
677 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
680 static void free_echo_data(struct hdp_echo_data *edata)
686 timeout_remove(edata->tid);
688 if (edata->buf != NULL)
695 static void health_channel_destroy(void *data)
697 struct hdp_channel *hdp_chan = data;
698 struct hdp_device *dev = hdp_chan->dev;
700 DBG("Destroy Health Channel %s", hdp_chan->path);
701 if (g_slist_find(dev->channels, hdp_chan) == NULL)
704 dev->channels = g_slist_remove(dev->channels, hdp_chan);
706 if (hdp_chan->mdep != HDP_MDEP_ECHO)
707 g_dbus_emit_signal(btd_get_dbus_connection(),
708 device_get_path(dev->dev),
709 HEALTH_DEVICE, "ChannelDeleted",
710 DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
713 if (hdp_chan == dev->fr) {
714 hdp_channel_unref(dev->fr);
719 hdp_channel_unref(hdp_chan);
722 static const GDBusMethodTable health_channels_methods[] = {
723 { GDBUS_ASYNC_METHOD("Acquire",
724 NULL, GDBUS_ARGS({ "fd", "h" }),
726 { GDBUS_METHOD("Release", NULL, NULL, channel_release) },
730 static const GDBusPropertyTable health_channels_properties[] = {
731 { "Device", "o", channel_property_get_device },
732 { "Application", "o", channel_property_get_application },
733 { "Type", "s", channel_property_get_type },
737 static struct hdp_channel *create_channel(struct hdp_device *dev,
739 struct mcap_mdl *mdl,
741 struct hdp_application *app,
744 struct hdp_channel *hdp_chann;
747 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
748 "HDP device uninitialized");
752 hdp_chann = g_new0(struct hdp_channel, 1);
753 hdp_chann->config = config;
754 hdp_chann->dev = health_device_ref(dev);
755 hdp_chann->mdlid = mdlid;
758 hdp_chann->mdl = mcap_mdl_ref(mdl);
761 hdp_chann->mdep = app->id;
762 hdp_chann->app = hdp_application_ref(app);
764 hdp_chann->edata = g_new0(struct hdp_echo_data, 1);
766 hdp_chann->path = g_strdup_printf("%s/chan%d",
767 device_get_path(hdp_chann->dev->dev),
770 dev->channels = g_slist_append(dev->channels,
771 hdp_channel_ref(hdp_chann));
773 if (hdp_chann->mdep == HDP_MDEP_ECHO)
774 return hdp_channel_ref(hdp_chann);
776 if (!g_dbus_register_interface(btd_get_dbus_connection(),
777 hdp_chann->path, HEALTH_CHANNEL,
778 health_channels_methods, NULL,
779 health_channels_properties, hdp_chann,
780 health_channel_destroy)) {
781 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
782 "Can't register the channel interface");
783 health_channel_destroy(hdp_chann);
787 return hdp_channel_ref(hdp_chann);
790 static void remove_channels(struct hdp_device *dev)
792 struct hdp_channel *chan;
795 while (dev->channels != NULL) {
796 chan = dev->channels->data;
798 path = g_strdup(chan->path);
799 if (!g_dbus_unregister_interface(btd_get_dbus_connection(),
800 path, HEALTH_CHANNEL))
801 health_channel_destroy(chan);
806 static void close_device_con(struct hdp_device *dev, gboolean cache)
808 if (dev->mcl == NULL)
811 mcap_close_mcl(dev->mcl, cache);
812 dev->mcl_conn = FALSE;
817 device_unref_mcl(dev);
818 remove_channels(dev);
820 if (!dev->sdp_present) {
823 path = device_get_path(dev->dev);
824 g_dbus_unregister_interface(btd_get_dbus_connection(),
825 path, HEALTH_DEVICE);
829 static int send_echo_data(int sock, const void *buf, uint32_t size)
831 const uint8_t *buf_b = buf;
834 while (sent < size) {
835 int n = write(sock, buf_b + sent, size - sent);
844 static gboolean serve_echo(GIOChannel *io_chan, GIOCondition cond,
847 struct hdp_channel *chan = data;
848 uint8_t buf[MCAP_DC_MTU];
851 if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
852 hdp_channel_unref(chan);
856 if (chan->edata->echo_done)
859 chan->edata->echo_done = TRUE;
861 fd = g_io_channel_unix_get_fd(io_chan);
863 len = read(fd, buf, sizeof(buf));
867 if (send_echo_data(fd, buf, len) >= 0)
871 close_device_con(chan->dev, FALSE);
872 hdp_channel_unref(chan);
876 static gboolean check_channel_conf(struct hdp_channel *chan)
884 fd = mcap_mdl_get_fd(chan->mdl);
887 io = g_io_channel_unix_new(fd);
889 if (!bt_io_get(io, &err,
890 BT_IO_OPT_MODE, &mode,
891 BT_IO_OPT_IMTU, &imtu,
892 BT_IO_OPT_OMTU, &omtu,
893 BT_IO_OPT_INVALID)) {
894 error("Error: %s", err->message);
895 g_io_channel_unref(io);
900 g_io_channel_unref(io);
902 switch (chan->config) {
903 case HDP_RELIABLE_DC:
904 if (mode != BT_IO_MODE_ERTM)
907 case HDP_STREAMING_DC:
908 if (mode != BT_IO_MODE_STREAMING)
912 error("Error: Connected with unknown configuration");
916 DBG("MDL imtu %d omtu %d Channel imtu %d omtu %d", imtu, omtu,
917 chan->imtu, chan->omtu);
924 if (chan->imtu != imtu || chan->omtu != omtu)
930 static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
932 struct hdp_device *dev = data;
933 struct hdp_channel *chan;
937 if (dev->ndc == NULL)
941 if (chan->mdl == NULL)
942 chan->mdl = mcap_mdl_ref(mdl);
944 if (g_slist_find(dev->channels, chan) == NULL)
945 dev->channels = g_slist_prepend(dev->channels,
946 hdp_channel_ref(chan));
948 if (!check_channel_conf(chan)) {
953 if (chan->mdep == HDP_MDEP_ECHO) {
957 fd = mcap_mdl_get_fd(chan->mdl);
961 chan->edata->echo_done = FALSE;
962 io = g_io_channel_unix_new(fd);
963 g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
964 serve_echo, hdp_channel_ref(chan));
965 g_io_channel_unref(io);
969 g_dbus_emit_signal(btd_get_dbus_connection(), device_get_path(dev->dev),
970 HEALTH_DEVICE, "ChannelConnected",
971 DBUS_TYPE_OBJECT_PATH, &chan->path,
977 dev->fr = hdp_channel_ref(chan);
979 g_dbus_emit_property_changed(btd_get_dbus_connection(),
980 device_get_path(dev->dev), HEALTH_DEVICE,
984 hdp_channel_unref(dev->ndc);
988 static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
990 /* struct hdp_device *dev = data; */
997 static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
999 struct hdp_device *dev = data;
1000 struct hdp_channel *chan;
1006 l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1012 path = g_strdup(chan->path);
1013 if (!g_dbus_unregister_interface(btd_get_dbus_connection(),
1014 path, HEALTH_CHANNEL))
1015 health_channel_destroy(chan);
1019 static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
1021 struct hdp_device *dev = data;
1025 if (dev->ndc == NULL)
1028 dev->ndc->mdl = mcap_mdl_ref(mdl);
1030 if (g_slist_find(dev->channels, dev->ndc) == NULL)
1031 dev->channels = g_slist_prepend(dev->channels,
1032 hdp_channel_ref(dev->ndc));
1034 if (dev->ndc->mdep != HDP_MDEP_ECHO)
1035 g_dbus_emit_signal(btd_get_dbus_connection(),
1036 device_get_path(dev->dev),
1037 HEALTH_DEVICE, "ChannelConnected",
1038 DBUS_TYPE_OBJECT_PATH, &dev->ndc->path,
1041 hdp_channel_unref(dev->ndc);
1045 static uint8_t hdp2l2cap_mode(uint8_t hdp_mode)
1047 return hdp_mode == HDP_STREAMING_DC ? BT_IO_MODE_STREAMING :
1051 static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
1052 uint16_t mdlid, uint8_t *conf, void *data)
1054 struct hdp_device *dev = data;
1055 struct hdp_application *app;
1059 DBG("Data channel request");
1061 if (mdepid == HDP_MDEP_ECHO) {
1063 case HDP_NO_PREFERENCE_DC:
1064 *conf = HDP_RELIABLE_DC;
1066 case HDP_RELIABLE_DC:
1068 case HDP_STREAMING_DC:
1069 return MCAP_CONFIGURATION_REJECTED;
1071 /* Special case defined in HDP spec 3.4. When an invalid
1072 * configuration is received we shall close the MCL when
1073 * we are still processing the callback. */
1074 close_device_con(dev, FALSE);
1075 return MCAP_CONFIGURATION_REJECTED; /* not processed */
1078 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1079 BT_IO_MODE_ERTM, &err)) {
1080 error("Error: %s", err->message);
1082 return MCAP_MDL_BUSY;
1085 dev->ndc = create_channel(dev, *conf, NULL, mdlid, NULL, NULL);
1086 if (dev->ndc == NULL)
1087 return MCAP_MDL_BUSY;
1089 return MCAP_SUCCESS;
1092 l = g_slist_find_custom(applications, &mdepid, cmp_app_id);
1094 return MCAP_INVALID_MDEP;
1098 /* Check if is the first dc if so,
1099 * only reliable configuration is allowed */
1101 case HDP_NO_PREFERENCE_DC:
1102 if (app->role == HDP_SINK)
1103 return MCAP_CONFIGURATION_REJECTED;
1104 else if (dev->fr && app->chan_type_set)
1105 *conf = app->chan_type;
1107 *conf = HDP_RELIABLE_DC;
1109 case HDP_STREAMING_DC:
1110 if (!dev->fr || app->role == HDP_SOURCE)
1111 return MCAP_CONFIGURATION_REJECTED;
1113 case HDP_RELIABLE_DC:
1114 if (app->role == HDP_SOURCE)
1115 return MCAP_CONFIGURATION_REJECTED;
1118 /* Special case defined in HDP spec 3.4. When an invalid
1119 * configuration is received we shall close the MCL when
1120 * we are still processing the callback. */
1121 close_device_con(dev, FALSE);
1122 return MCAP_CONFIGURATION_REJECTED; /* not processed */
1125 l = g_slist_find_custom(dev->channels, &mdlid, cmp_chan_mdlid);
1127 struct hdp_channel *chan = l->data;
1130 path = g_strdup(chan->path);
1131 g_dbus_unregister_interface(btd_get_dbus_connection(),
1132 path, HEALTH_CHANNEL);
1136 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1137 hdp2l2cap_mode(*conf), &err)) {
1138 error("Error: %s", err->message);
1140 return MCAP_MDL_BUSY;
1143 dev->ndc = create_channel(dev, *conf, NULL, mdlid, app, NULL);
1144 if (dev->ndc == NULL)
1145 return MCAP_MDL_BUSY;
1147 return MCAP_SUCCESS;
1150 static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
1152 struct hdp_device *dev = data;
1153 struct hdp_channel *chan;
1157 l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1159 return MCAP_INVALID_MDL;
1163 if (dev->fr == NULL && chan->config != HDP_RELIABLE_DC &&
1164 chan->mdep != HDP_MDEP_ECHO)
1165 return MCAP_UNSPECIFIED_ERROR;
1167 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1168 hdp2l2cap_mode(chan->config), &err)) {
1169 error("Error: %s", err->message);
1171 return MCAP_MDL_BUSY;
1174 dev->ndc = hdp_channel_ref(chan);
1176 return MCAP_SUCCESS;
1179 gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err)
1183 if (device->mcl == NULL)
1186 ret = mcap_mcl_set_cb(device->mcl, device, err,
1187 MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
1188 MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
1189 MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
1190 MCAP_MDL_CB_ABORTED, hdp_mcap_mdl_aborted_cb,
1191 MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
1192 MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
1193 MCAP_MDL_CB_INVALID);
1197 error("Can't set mcl callbacks, closing mcl");
1198 close_device_con(device, TRUE);
1203 static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
1205 struct hdp_device *hdp_device;
1209 mcap_mcl_get_addr(mcl, &addr);
1210 l = g_slist_find_custom(devices, &addr, cmp_dev_addr);
1212 struct hdp_adapter *hdp_adapter = data;
1213 struct btd_device *device;
1215 device = btd_adapter_get_device(hdp_adapter->btd_adapter,
1216 &addr, BDADDR_BREDR);
1219 hdp_device = create_health_device(device);
1222 devices = g_slist_append(devices, hdp_device);
1224 hdp_device = l->data;
1226 hdp_device->mcl = mcap_mcl_ref(mcl);
1227 hdp_device->mcl_conn = TRUE;
1229 DBG("New mcl connected from %s", device_get_path(hdp_device->dev));
1231 hdp_set_mcl_cb(hdp_device, NULL);
1234 static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
1236 struct hdp_device *hdp_device;
1239 l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1243 hdp_device = l->data;
1244 hdp_device->mcl_conn = TRUE;
1246 DBG("MCL reconnected %s", device_get_path(hdp_device->dev));
1248 hdp_set_mcl_cb(hdp_device, NULL);
1251 static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
1253 struct hdp_device *hdp_device;
1256 l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1260 hdp_device = l->data;
1261 hdp_device->mcl_conn = FALSE;
1263 DBG("Mcl disconnected %s", device_get_path(hdp_device->dev));
1266 static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
1268 struct hdp_device *hdp_device;
1272 l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1276 hdp_device = l->data;
1277 device_unref_mcl(hdp_device);
1279 if (hdp_device->sdp_present)
1282 /* Because remote device hasn't announced an HDP record */
1283 /* the Bluetooth daemon won't notify when the device shall */
1284 /* be removed. Then we have to remove the HealthDevice */
1285 /* interface manually */
1286 path = device_get_path(hdp_device->dev);
1287 g_dbus_unregister_interface(btd_get_dbus_connection(),
1288 path, HEALTH_DEVICE);
1289 DBG("Mcl uncached %s", path);
1292 static void check_devices_mcl(void)
1294 struct hdp_device *dev;
1295 GSList *l, *to_delete = NULL;
1297 for (l = devices; l; l = l->next) {
1299 device_unref_mcl(dev);
1301 if (!dev->sdp_present)
1302 to_delete = g_slist_append(to_delete, dev);
1304 remove_channels(dev);
1307 for (l = to_delete; l; l = l->next) {
1310 path = device_get_path(dev->dev);
1311 g_dbus_unregister_interface(btd_get_dbus_connection(),
1312 path, HEALTH_DEVICE);
1315 g_slist_free(to_delete);
1318 static void release_adapter_instance(struct hdp_adapter *hdp_adapter)
1320 if (hdp_adapter->mi == NULL)
1323 check_devices_mcl();
1324 mcap_release_instance(hdp_adapter->mi);
1325 mcap_instance_unref(hdp_adapter->mi);
1326 hdp_adapter->mi = NULL;
1329 static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
1332 const bdaddr_t *src;
1334 if (applications == NULL) {
1335 release_adapter_instance(hdp_adapter);
1339 if (hdp_adapter->mi != NULL)
1342 src = btd_adapter_get_address(hdp_adapter->btd_adapter);
1344 hdp_adapter->mi = mcap_create_instance(src,
1345 BT_IO_SEC_MEDIUM, 0, 0,
1346 mcl_connected, mcl_reconnected,
1347 mcl_disconnected, mcl_uncached,
1348 NULL, /* CSP is not used by now */
1350 if (hdp_adapter->mi == NULL) {
1351 error("Error creating the MCAP instance: %s", err->message);
1356 hdp_adapter->ccpsm = mcap_get_ctrl_psm(hdp_adapter->mi, &err);
1358 error("Error getting MCAP control PSM: %s", err->message);
1362 hdp_adapter->dcpsm = mcap_get_data_psm(hdp_adapter->mi, &err);
1364 error("Error getting MCAP data PSM: %s", err->message);
1369 if (hdp_update_sdp_record(hdp_adapter, applications))
1371 error("Error updating the SDP record");
1374 release_adapter_instance(hdp_adapter);
1381 static void update_adapter_cb(void *data, void *user_data)
1383 update_adapter(data);
1386 int hdp_adapter_register(struct btd_adapter *adapter)
1388 struct hdp_adapter *hdp_adapter;
1390 hdp_adapter = g_new0(struct hdp_adapter, 1);
1391 hdp_adapter->btd_adapter = btd_adapter_ref(adapter);
1393 if(!update_adapter(hdp_adapter))
1396 adapters = g_slist_append(adapters, hdp_adapter);
1401 btd_adapter_unref(hdp_adapter->btd_adapter);
1402 g_free(hdp_adapter);
1406 void hdp_adapter_unregister(struct btd_adapter *adapter)
1408 struct hdp_adapter *hdp_adapter;
1411 l = g_slist_find_custom(adapters, adapter, cmp_adapter);
1416 hdp_adapter = l->data;
1417 adapters = g_slist_remove(adapters, hdp_adapter);
1418 if (hdp_adapter->sdp_handler > 0)
1419 adapter_service_remove(adapter, hdp_adapter->sdp_handler);
1420 release_adapter_instance(hdp_adapter);
1421 btd_adapter_unref(hdp_adapter->btd_adapter);
1422 g_free(hdp_adapter);
1425 static void delete_echo_channel_cb(GError *err, gpointer chan)
1427 if (err != NULL && err->code != MCAP_INVALID_MDL) {
1428 /* TODO: Decide if more action is required here */
1429 error("Error deleting echo channel: %s", err->message);
1433 health_channel_destroy(chan);
1436 static void delete_echo_channel(struct hdp_channel *chan)
1440 if (!chan->dev->mcl_conn) {
1441 error("Echo channel cannot be deleted: mcl closed");
1445 if (mcap_delete_mdl(chan->mdl, delete_echo_channel_cb,
1446 hdp_channel_ref(chan),
1447 (GDestroyNotify) hdp_channel_unref, &err))
1450 hdp_channel_unref(chan);
1451 error("Error deleting the echo channel: %s", err->message);
1454 /* TODO: Decide if more action is required here */
1457 static void abort_echo_channel_cb(GError *err, gpointer data)
1459 struct hdp_channel *chan = data;
1461 if (err != NULL && err->code != MCAP_ERROR_INVALID_OPERATION) {
1462 error("Aborting error: %s", err->message);
1463 if (err->code == MCAP_INVALID_MDL) {
1464 /* MDL is removed from MCAP so we can */
1465 /* free the data channel without sending */
1466 /* a MD_DELETE_MDL_REQ */
1467 /* TODO review the above comment */
1468 /* hdp_channel_unref(chan); */
1473 delete_echo_channel(chan);
1476 static void destroy_create_dc_data(gpointer data)
1478 struct hdp_create_dc *dc_data = data;
1480 hdp_create_data_unref(dc_data);
1483 static void *generate_echo_packet(void)
1488 buf = g_malloc(HDP_ECHO_LEN);
1491 for(i = 0; i < HDP_ECHO_LEN; i++)
1492 buf[i] = rand() % UINT8_MAX;
1497 static gboolean check_echo(GIOChannel *io_chan, GIOCondition cond,
1500 struct hdp_tmp_dc_data *hdp_conn = data;
1501 struct hdp_echo_data *edata = hdp_conn->hdp_chann->edata;
1502 struct hdp_channel *chan = hdp_conn->hdp_chann;
1503 uint8_t buf[MCAP_DC_MTU];
1508 if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
1513 fd = g_io_channel_unix_get_fd(io_chan);
1515 len = read(fd, buf, sizeof(buf));
1516 if (len != HDP_ECHO_LEN) {
1521 value = (memcmp(buf, edata->buf, len) == 0);
1524 reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_BOOLEAN, &value,
1526 g_dbus_send_message(btd_get_dbus_connection(), reply);
1527 timeout_remove(edata->tid);
1533 close_device_con(chan->dev, FALSE);
1535 delete_echo_channel(chan);
1536 hdp_tmp_dc_data_unref(hdp_conn);
1541 static bool echo_timeout(gpointer data)
1543 struct hdp_channel *chan = data;
1547 error("Error: Echo request timeout");
1548 chan->edata->tid = 0;
1550 fd = mcap_mdl_get_fd(chan->mdl);
1554 io = g_io_channel_unix_new(fd);
1555 g_io_channel_shutdown(io, TRUE, NULL);
1560 static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
1563 DBusConnection *conn = btd_get_dbus_connection();
1564 struct hdp_tmp_dc_data *hdp_conn = data;
1565 struct hdp_echo_data *edata;
1566 GError *gerr = NULL;
1572 reply = g_dbus_create_error(hdp_conn->msg,
1573 ERROR_INTERFACE ".HealthError",
1574 "%s", err->message);
1575 g_dbus_send_message(conn, reply);
1577 /* Send abort request because remote */
1578 /* side is now in PENDING state. */
1579 if (!mcap_mdl_abort(hdp_conn->hdp_chann->mdl,
1580 abort_echo_channel_cb,
1581 hdp_channel_ref(hdp_conn->hdp_chann),
1582 (GDestroyNotify) hdp_channel_unref,
1584 error("%s", gerr->message);
1586 hdp_channel_unref(hdp_conn->hdp_chann);
1591 fd = mcap_mdl_get_fd(hdp_conn->hdp_chann->mdl);
1593 reply = g_dbus_create_error(hdp_conn->msg,
1594 ERROR_INTERFACE ".HealthError",
1595 "Can't write in echo channel");
1596 g_dbus_send_message(conn, reply);
1597 delete_echo_channel(hdp_conn->hdp_chann);
1601 edata = hdp_conn->hdp_chann->edata;
1602 edata->buf = generate_echo_packet();
1603 send_echo_data(fd, edata->buf, HDP_ECHO_LEN);
1605 io = g_io_channel_unix_new(fd);
1606 g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
1607 check_echo, hdp_tmp_dc_data_ref(hdp_conn));
1609 edata->tid = timeout_add_seconds(ECHO_TIMEOUT, echo_timeout,
1610 hdp_channel_ref(hdp_conn->hdp_chann),
1611 (timeout_destroy_func_t) hdp_channel_unref);
1613 g_io_channel_unref(io);
1616 static void delete_mdl_cb(GError *err, gpointer data)
1619 error("Deleting error: %s", err->message);
1622 static void abort_and_del_mdl_cb(GError *err, gpointer data)
1624 struct mcap_mdl *mdl = data;
1625 GError *gerr = NULL;
1628 error("%s", err->message);
1629 if (err->code == MCAP_INVALID_MDL) {
1630 /* MDL is removed from MCAP so we don't */
1631 /* need to delete it. */
1636 if (!mcap_delete_mdl(mdl, delete_mdl_cb, NULL, NULL, &gerr)) {
1637 error("%s", gerr->message);
1642 static void abort_mdl_connection_cb(GError *err, gpointer data)
1644 struct hdp_tmp_dc_data *hdp_conn = data;
1645 struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1648 error("Aborting error: %s", err->message);
1650 /* Connection operation has failed but we have to */
1651 /* notify the channel created at MCAP level */
1652 if (hdp_chann->mdep != HDP_MDEP_ECHO)
1653 g_dbus_emit_signal(btd_get_dbus_connection(),
1654 device_get_path(hdp_chann->dev->dev),
1655 HEALTH_DEVICE, "ChannelConnected",
1656 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1660 static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
1662 DBusConnection *conn = btd_get_dbus_connection();
1663 struct hdp_tmp_dc_data *hdp_conn = data;
1664 struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1665 struct hdp_device *dev = hdp_chann->dev;
1667 GError *gerr = NULL;
1670 error("%s", err->message);
1671 reply = g_dbus_create_reply(hdp_conn->msg,
1672 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1674 g_dbus_send_message(conn, reply);
1676 /* Send abort request because remote side */
1677 /* is now in PENDING state */
1678 if (!mcap_mdl_abort(hdp_chann->mdl, abort_mdl_connection_cb,
1679 hdp_tmp_dc_data_ref(hdp_conn),
1680 hdp_tmp_dc_data_destroy, &gerr)) {
1681 hdp_tmp_dc_data_unref(hdp_conn);
1682 error("%s", gerr->message);
1688 reply = g_dbus_create_reply(hdp_conn->msg,
1689 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1691 g_dbus_send_message(conn, reply);
1693 g_dbus_emit_signal(conn, device_get_path(hdp_chann->dev->dev),
1694 HEALTH_DEVICE, "ChannelConnected",
1695 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1698 if (!check_channel_conf(hdp_chann)) {
1699 close_mdl(hdp_chann);
1703 if (dev->fr != NULL)
1706 dev->fr = hdp_channel_ref(hdp_chann);
1708 g_dbus_emit_property_changed(btd_get_dbus_connection(),
1709 device_get_path(dev->dev), HEALTH_DEVICE,
1713 static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
1714 GError *err, gpointer data)
1716 DBusConnection *conn = btd_get_dbus_connection();
1717 struct hdp_create_dc *user_data = data;
1718 struct hdp_tmp_dc_data *hdp_conn;
1719 struct hdp_channel *hdp_chan;
1720 GError *gerr = NULL;
1724 reply = g_dbus_create_error(user_data->msg,
1725 ERROR_INTERFACE ".HealthError",
1726 "%s", err->message);
1727 g_dbus_send_message(conn, reply);
1731 if (user_data->mdep != HDP_MDEP_ECHO &&
1732 user_data->config == HDP_NO_PREFERENCE_DC) {
1733 if (user_data->dev->fr == NULL && conf != HDP_RELIABLE_DC) {
1734 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1735 "Data channel aborted, first data "
1736 "channel should be reliable");
1738 } else if (conf == HDP_NO_PREFERENCE_DC ||
1739 conf > HDP_STREAMING_DC) {
1740 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1741 "Data channel aborted, "
1742 "configuration error");
1747 hdp_chan = create_channel(user_data->dev, conf, mdl,
1748 mcap_mdl_get_mdlid(mdl),
1749 user_data->app, &gerr);
1750 if (hdp_chan == NULL)
1753 hdp_conn = g_new0(struct hdp_tmp_dc_data, 1);
1754 hdp_conn->msg = dbus_message_ref(user_data->msg);
1755 hdp_conn->hdp_chann = hdp_chan;
1756 hdp_conn->cb = user_data->cb;
1757 hdp_chan->mdep = user_data->mdep;
1759 if (hdp_get_dcpsm(hdp_chan->dev, hdp_get_dcpsm_cb,
1760 hdp_tmp_dc_data_ref(hdp_conn),
1761 hdp_tmp_dc_data_destroy, &gerr))
1764 error("%s", gerr->message);
1767 reply = g_dbus_create_reply(hdp_conn->msg,
1768 DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
1770 g_dbus_send_message(conn, reply);
1771 hdp_tmp_dc_data_unref(hdp_conn);
1773 /* Send abort request because remote side is now in PENDING state */
1774 if (!mcap_mdl_abort(hdp_chan->mdl, abort_mdl_connection_cb,
1775 hdp_tmp_dc_data_ref(hdp_conn),
1776 hdp_tmp_dc_data_destroy, &gerr)) {
1777 hdp_tmp_dc_data_unref(hdp_conn);
1778 error("%s", gerr->message);
1785 reply = g_dbus_create_error(user_data->msg,
1786 ERROR_INTERFACE ".HealthError",
1787 "%s", gerr->message);
1788 g_dbus_send_message(conn, reply);
1791 /* Send abort request because remote side is now in PENDING */
1792 /* state. Then we have to delete it because we couldn't */
1793 /* register the HealthChannel interface */
1794 if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl),
1795 (GDestroyNotify) mcap_mdl_unref, &gerr)) {
1796 error("%s", gerr->message);
1798 mcap_mdl_unref(mdl);
1802 static void device_create_dc_cb(gpointer user_data, GError *err)
1804 DBusConnection *conn = btd_get_dbus_connection();
1805 struct hdp_create_dc *data = user_data;
1807 GError *gerr = NULL;
1810 reply = g_dbus_create_error(data->msg,
1811 ERROR_INTERFACE ".HealthError",
1812 "%s", err->message);
1813 g_dbus_send_message(conn, reply);
1817 if (data->dev->mcl == NULL) {
1818 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1823 hdp_create_data_ref(data);
1825 if (mcap_create_mdl(data->dev->mcl, data->mdep, data->config,
1826 device_create_mdl_cb, data,
1827 destroy_create_dc_data, &gerr))
1829 hdp_create_data_unref(data);
1832 reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
1833 "%s", gerr->message);
1835 g_dbus_send_message(conn, reply);
1838 static DBusMessage *device_echo(DBusConnection *conn,
1839 DBusMessage *msg, void *user_data)
1841 struct hdp_device *device = user_data;
1842 struct hdp_create_dc *data;
1846 data = g_new0(struct hdp_create_dc, 1);
1847 data->dev = health_device_ref(device);
1848 data->mdep = HDP_MDEP_ECHO;
1849 data->config = HDP_RELIABLE_DC;
1850 data->msg = dbus_message_ref(msg);
1851 data->cb = hdp_echo_connect_cb;
1852 hdp_create_data_ref(data);
1854 if (device->mcl_conn && device->mcl) {
1855 if (mcap_create_mdl(device->mcl, data->mdep, data->config,
1856 device_create_mdl_cb, data,
1857 destroy_create_dc_data, &err))
1862 if (hdp_establish_mcl(data->dev, device_create_dc_cb,
1863 data, destroy_create_dc_data, &err))
1867 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1868 "%s", err->message);
1870 hdp_create_data_unref(data);
1874 static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
1876 DBusConnection *conn = btd_get_dbus_connection();
1877 struct hdp_create_dc *dc_data, *user_data = data;
1879 GError *gerr = NULL;
1882 reply = g_dbus_create_error(user_data->msg,
1883 ERROR_INTERFACE ".HealthError",
1884 "%s", err->message);
1885 g_dbus_send_message(conn, reply);
1889 dc_data = hdp_create_data_ref(user_data);
1890 dc_data->mdep = mdep;
1892 if (user_data->dev->mcl_conn) {
1893 device_create_dc_cb(dc_data, NULL);
1894 hdp_create_data_unref(dc_data);
1898 if (hdp_establish_mcl(dc_data->dev, device_create_dc_cb,
1899 dc_data, destroy_create_dc_data, &gerr))
1902 reply = g_dbus_create_error(user_data->msg,
1903 ERROR_INTERFACE ".HealthError",
1904 "%s", gerr->message);
1905 hdp_create_data_unref(dc_data);
1907 g_dbus_send_message(conn, reply);
1910 static DBusMessage *device_create_channel(DBusConnection *conn,
1911 DBusMessage *msg, void *user_data)
1913 struct hdp_device *device = user_data;
1914 struct hdp_application *app;
1915 struct hdp_create_dc *data;
1916 char *app_path, *conf;
1922 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &app_path,
1923 DBUS_TYPE_STRING, &conf,
1925 return btd_error_invalid_args(msg);
1927 l = g_slist_find_custom(applications, app_path, cmp_app);
1929 return btd_error_invalid_args(msg);
1933 if (g_ascii_strcasecmp("reliable", conf) == 0)
1934 config = HDP_RELIABLE_DC;
1935 else if (g_ascii_strcasecmp("streaming", conf) == 0)
1936 config = HDP_STREAMING_DC;
1937 else if (g_ascii_strcasecmp("any", conf) == 0)
1938 config = HDP_NO_PREFERENCE_DC;
1940 return btd_error_invalid_args(msg);
1942 if (app->role == HDP_SINK && config != HDP_NO_PREFERENCE_DC)
1943 return btd_error_invalid_args(msg);
1945 if (app->role == HDP_SOURCE && config == HDP_NO_PREFERENCE_DC)
1946 return btd_error_invalid_args(msg);
1948 if (!device->fr && config == HDP_STREAMING_DC)
1949 return btd_error_invalid_args(msg);
1951 data = g_new0(struct hdp_create_dc, 1);
1952 data->dev = health_device_ref(device);
1953 data->config = config;
1954 data->app = hdp_application_ref(app);
1955 data->msg = dbus_message_ref(msg);
1956 data->cb = hdp_mdl_conn_cb;
1958 if (hdp_get_mdep(device, l->data, device_get_mdep_cb,
1959 hdp_create_data_ref(data),
1960 destroy_create_dc_data, &err))
1963 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1964 "%s", err->message);
1966 hdp_create_data_unref(data);
1970 static void hdp_mdl_delete_cb(GError *err, gpointer data)
1972 DBusConnection *conn = btd_get_dbus_connection();
1973 struct hdp_tmp_dc_data *del_data = data;
1977 if (err != NULL && err->code != MCAP_INVALID_MDL) {
1978 reply = g_dbus_create_error(del_data->msg,
1979 ERROR_INTERFACE ".HealthError",
1980 "%s", err->message);
1981 g_dbus_send_message(conn, reply);
1985 path = g_strdup(del_data->hdp_chann->path);
1986 g_dbus_unregister_interface(conn, path, HEALTH_CHANNEL);
1989 reply = g_dbus_create_reply(del_data->msg, DBUS_TYPE_INVALID);
1990 g_dbus_send_message(conn, reply);
1993 static void hdp_continue_del_cb(gpointer user_data, GError *err)
1995 DBusConnection *conn = btd_get_dbus_connection();
1996 struct hdp_tmp_dc_data *del_data = user_data;
1997 GError *gerr = NULL;
2001 reply = g_dbus_create_error(del_data->msg,
2002 ERROR_INTERFACE ".HealthError",
2003 "%s", err->message);
2004 g_dbus_send_message(conn, reply);
2008 if (mcap_delete_mdl(del_data->hdp_chann->mdl, hdp_mdl_delete_cb,
2009 hdp_tmp_dc_data_ref(del_data),
2010 hdp_tmp_dc_data_destroy, &gerr))
2013 reply = g_dbus_create_error(del_data->msg,
2014 ERROR_INTERFACE ".HealthError",
2015 "%s", gerr->message);
2016 hdp_tmp_dc_data_unref(del_data);
2018 g_dbus_send_message(conn, reply);
2021 static DBusMessage *device_destroy_channel(DBusConnection *conn,
2022 DBusMessage *msg, void *user_data)
2024 struct hdp_device *device = user_data;
2025 struct hdp_tmp_dc_data *del_data;
2026 struct hdp_channel *hdp_chan;
2032 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
2033 DBUS_TYPE_INVALID)){
2034 return btd_error_invalid_args(msg);
2037 l = g_slist_find_custom(device->channels, path, cmp_chan_path);
2039 return btd_error_invalid_args(msg);
2042 del_data = g_new0(struct hdp_tmp_dc_data, 1);
2043 del_data->msg = dbus_message_ref(msg);
2044 del_data->hdp_chann = hdp_channel_ref(hdp_chan);
2046 if (device->mcl_conn) {
2047 if (mcap_delete_mdl(hdp_chan->mdl, hdp_mdl_delete_cb,
2048 hdp_tmp_dc_data_ref(del_data),
2049 hdp_tmp_dc_data_destroy, &err))
2054 if (hdp_establish_mcl(device, hdp_continue_del_cb,
2055 hdp_tmp_dc_data_ref(del_data),
2056 hdp_tmp_dc_data_destroy, &err))
2060 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
2061 "%s", err->message);
2062 hdp_tmp_dc_data_unref(del_data);
2067 static gboolean dev_property_exists_main_channel(
2068 const GDBusPropertyTable *property, void *data)
2070 struct hdp_device *device = data;
2071 return device->fr != NULL;
2074 static gboolean dev_property_get_main_channel(
2075 const GDBusPropertyTable *property,
2076 DBusMessageIter *iter, void *data)
2078 struct hdp_device *device = data;
2080 if (device->fr == NULL)
2083 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2089 static void health_device_destroy(void *data)
2091 struct hdp_device *device = data;
2093 DBG("Unregistered interface %s on path %s", HEALTH_DEVICE,
2094 device_get_path(device->dev));
2096 remove_channels(device);
2097 if (device->ndc != NULL) {
2098 hdp_channel_unref(device->ndc);
2102 devices = g_slist_remove(devices, device);
2103 health_device_unref(device);
2106 static const GDBusMethodTable health_device_methods[] = {
2107 { GDBUS_ASYNC_METHOD("Echo",
2108 NULL, GDBUS_ARGS({ "value", "b" }), device_echo) },
2109 { GDBUS_ASYNC_METHOD("CreateChannel",
2110 GDBUS_ARGS({ "application", "o" },
2111 { "configuration", "s" }),
2112 GDBUS_ARGS({ "channel", "o" }),
2113 device_create_channel) },
2114 { GDBUS_ASYNC_METHOD("DestroyChannel",
2115 GDBUS_ARGS({ "channel", "o" }), NULL,
2116 device_destroy_channel) },
2120 static const GDBusSignalTable health_device_signals[] = {
2121 { GDBUS_SIGNAL("ChannelConnected",
2122 GDBUS_ARGS({ "channel", "o" })) },
2123 { GDBUS_SIGNAL("ChannelDeleted",
2124 GDBUS_ARGS({ "channel", "o" })) },
2128 static const GDBusPropertyTable health_device_properties[] = {
2129 { "MainChannel", "o", dev_property_get_main_channel, NULL,
2130 dev_property_exists_main_channel },
2134 static struct hdp_device *create_health_device(struct btd_device *device)
2136 struct btd_adapter *adapter = device_get_adapter(device);
2137 const char *path = device_get_path(device);
2138 struct hdp_device *dev;
2144 dev = g_new0(struct hdp_device, 1);
2145 dev->dev = btd_device_ref(device);
2146 health_device_ref(dev);
2148 l = g_slist_find_custom(adapters, adapter, cmp_adapter);
2152 dev->hdp_adapter = l->data;
2154 if (!g_dbus_register_interface(btd_get_dbus_connection(),
2155 path, HEALTH_DEVICE,
2156 health_device_methods,
2157 health_device_signals,
2158 health_device_properties,
2159 dev, health_device_destroy)) {
2160 error("D-Bus failed to register %s interface", HEALTH_DEVICE);
2164 DBG("Registered interface %s on path %s", HEALTH_DEVICE, path);
2168 health_device_unref(dev);
2172 int hdp_device_register(struct btd_device *device)
2174 struct hdp_device *hdev;
2177 l = g_slist_find_custom(devices, device, cmp_device);
2180 hdev->sdp_present = TRUE;
2184 hdev = create_health_device(device);
2188 hdev->sdp_present = TRUE;
2190 devices = g_slist_prepend(devices, hdev);
2194 void hdp_device_unregister(struct btd_device *device)
2196 struct hdp_device *hdp_dev;
2200 l = g_slist_find_custom(devices, device, cmp_device);
2205 path = device_get_path(hdp_dev->dev);
2206 g_dbus_unregister_interface(btd_get_dbus_connection(),
2207 path, HEALTH_DEVICE);
2210 int hdp_manager_start(void)
2212 DBG("Starting Health manager");
2214 if (!g_dbus_register_interface(btd_get_dbus_connection(),
2215 MANAGER_PATH, HEALTH_MANAGER,
2216 health_manager_methods, NULL, NULL,
2217 NULL, manager_path_unregister)) {
2218 error("D-Bus failed to register %s interface", HEALTH_MANAGER);
2225 void hdp_manager_stop(void)
2227 g_dbus_unregister_interface(btd_get_dbus_connection(),
2228 MANAGER_PATH, HEALTH_MANAGER);
2230 DBG("Stopped Health manager");
2233 struct hdp_device *health_device_ref(struct hdp_device *hdp_dev)
2237 DBG("(%p): ref=%d", hdp_dev, hdp_dev->ref);
2242 void health_device_unref(struct hdp_device *hdp_dev)
2246 DBG("(%p): ref=%d", hdp_dev, hdp_dev->ref);
2248 if (hdp_dev->ref > 0)
2251 free_health_device(hdp_dev);