3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <bluetooth/l2cap.h>
32 #include <dbus-common.h>
40 #include "hdp_types.h"
45 #define ECHO_TIMEOUT 1 /* second */
46 #define HDP_ECHO_LEN 15
48 static DBusConnection *connection = NULL;
50 static GSList *applications = NULL;
51 static GSList *devices = NULL;
52 static uint8_t next_app_id = HDP_MDEP_INITIAL;
54 static GSList *adapters;
56 static gboolean update_adapter(struct hdp_adapter *adapter);
57 static struct hdp_device *create_health_device(DBusConnection *conn,
58 struct btd_device *device);
59 static void free_echo_data(struct hdp_echo_data *edata);
61 struct hdp_create_dc {
64 struct hdp_application *app;
65 struct hdp_device *dev;
69 mcap_mdl_operation_cb cb;
72 struct hdp_tmp_dc_data {
75 struct hdp_channel *hdp_chann;
77 mcap_mdl_operation_cb cb;
80 struct hdp_echo_data {
81 gboolean echo_done; /* Is a echo was already done */
82 gpointer buf; /* echo packet sent */
83 uint tid; /* echo timeout */
86 static struct hdp_channel *hdp_channel_ref(struct hdp_channel *chan)
93 DBG("health_channel_ref(%p): ref=%d", chan, chan->ref);
97 static void free_health_channel(struct hdp_channel *chan)
99 if (chan->mdep == HDP_MDEP_ECHO) {
100 free_echo_data(chan->edata);
104 mcap_mdl_unref(chan->mdl);
105 hdp_application_unref(chan->app);
106 health_device_unref(chan->dev);
111 static void hdp_channel_unref(struct hdp_channel *chan)
117 DBG("health_channel_unref(%p): ref=%d", chan, chan->ref);
122 free_health_channel(chan);
125 static void free_hdp_create_dc(struct hdp_create_dc *dc_data)
127 dbus_message_unref(dc_data->msg);
128 dbus_connection_unref(dc_data->conn);
129 hdp_application_unref(dc_data->app);
130 health_device_unref(dc_data->dev);
135 static struct hdp_create_dc *hdp_create_data_ref(struct hdp_create_dc *dc_data)
139 DBG("hdp_create_data_ref(%p): ref=%d", dc_data, dc_data->ref);
144 static void hdp_create_data_unref(struct hdp_create_dc *dc_data)
148 DBG("hdp_create_data_unref(%p): ref=%d", dc_data, dc_data->ref);
150 if (dc_data->ref > 0)
153 free_hdp_create_dc(dc_data);
156 static void free_hdp_conn_dc(struct hdp_tmp_dc_data *data)
158 dbus_message_unref(data->msg);
159 dbus_connection_unref(data->conn);
160 hdp_channel_unref(data->hdp_chann);
165 static struct hdp_tmp_dc_data *hdp_tmp_dc_data_ref(struct hdp_tmp_dc_data *data)
169 DBG("hdp_conn_data_ref(%p): ref=%d", data, data->ref);
174 static void hdp_tmp_dc_data_unref(struct hdp_tmp_dc_data *data)
178 DBG("hdp_conn_data_unref(%p): ref=%d", data, data->ref);
183 free_hdp_conn_dc(data);
186 static int cmp_app_id(gconstpointer a, gconstpointer b)
188 const struct hdp_application *app = a;
189 const uint8_t *id = b;
191 return app->id - *id;
194 static int cmp_adapter(gconstpointer a, gconstpointer b)
196 const struct hdp_adapter *hdp_adapter = a;
197 const struct btd_adapter *adapter = b;
199 if (hdp_adapter->btd_adapter == adapter)
205 static int cmp_device(gconstpointer a, gconstpointer b)
207 const struct hdp_device *hdp_device = a;
208 const struct btd_device *device = b;
210 if (hdp_device->dev == device)
216 static gint cmp_dev_addr(gconstpointer a, gconstpointer dst)
218 const struct hdp_device *device = a;
221 device_get_address(device->dev, &addr, NULL);
222 return bacmp(&addr, dst);
225 static gint cmp_dev_mcl(gconstpointer a, gconstpointer mcl)
227 const struct hdp_device *device = a;
229 if (mcl == device->mcl)
234 static gint cmp_chan_mdlid(gconstpointer a, gconstpointer b)
236 const struct hdp_channel *chan = a;
237 const uint16_t *mdlid = b;
239 return chan->mdlid - *mdlid;
242 static gint cmp_chan_path(gconstpointer a, gconstpointer b)
244 const struct hdp_channel *chan = a;
245 const char *path = b;
247 return g_ascii_strcasecmp(chan->path, path);
250 static gint cmp_chan_mdl(gconstpointer a, gconstpointer mdl)
252 const struct hdp_channel *chan = a;
254 if (chan->mdl == mdl)
259 static uint8_t get_app_id(void)
261 uint8_t id = next_app_id;
264 GSList *l = g_slist_find_custom(applications, &id, cmp_app_id);
267 next_app_id = (id % HDP_MDEP_FINAL) + 1;
270 id = (id % HDP_MDEP_FINAL) + 1;
271 } while (id != next_app_id);
273 /* No more ids available */
277 static int cmp_app(gconstpointer a, gconstpointer b)
279 const struct hdp_application *app = a;
281 return g_strcmp0(app->path, b);
284 static gboolean set_app_path(struct hdp_application *app)
286 app->id = get_app_id();
289 app->path = g_strdup_printf(MANAGER_PATH "/health_app_%d", app->id);
294 static void device_unref_mcl(struct hdp_device *hdp_device)
296 if (hdp_device->mcl == NULL)
299 mcap_close_mcl(hdp_device->mcl, FALSE);
300 mcap_mcl_unref(hdp_device->mcl);
301 hdp_device->mcl = NULL;
302 hdp_device->mcl_conn = FALSE;
305 static void free_health_device(struct hdp_device *device)
307 if (device->conn != NULL) {
308 dbus_connection_unref(device->conn);
312 if (device->dev != NULL) {
313 btd_device_unref(device->dev);
317 device_unref_mcl(device);
322 static void remove_application(struct hdp_application *app)
324 DBG("Application %s deleted", app->path);
325 hdp_application_unref(app);
327 g_slist_foreach(adapters, (GFunc) update_adapter, NULL);
330 static void client_disconnected(DBusConnection *conn, void *user_data)
332 struct hdp_application *app = user_data;
334 DBG("Client disconnected from the bus, deleting hdp application");
335 applications = g_slist_remove(applications, app);
337 app->dbus_watcher = 0; /* Watcher shouldn't be freed in this case */
338 remove_application(app);
341 static DBusMessage *manager_create_application(DBusConnection *conn,
342 DBusMessage *msg, void *user_data)
344 struct hdp_application *app;
346 DBusMessageIter iter;
349 dbus_message_iter_init(msg, &iter);
350 app = hdp_get_app_config(&iter, &err);
353 return btd_error_invalid_args(msg);
356 name = dbus_message_get_sender(msg);
358 hdp_application_unref(app);
359 return g_dbus_create_error(msg,
360 ERROR_INTERFACE ".HealthError",
361 "Can't get sender name");
364 if (!set_app_path(app)) {
365 hdp_application_unref(app);
366 return g_dbus_create_error(msg,
367 ERROR_INTERFACE ".HealthError",
368 "Can't get a valid id for the application");
371 app->oname = g_strdup(name);
372 app->conn = dbus_connection_ref(conn);
374 applications = g_slist_prepend(applications, app);
376 app->dbus_watcher = g_dbus_add_disconnect_watch(conn, name,
377 client_disconnected, app, NULL);
378 g_slist_foreach(adapters, (GFunc) update_adapter, NULL);
380 DBG("Health application created with id %s", app->path);
382 return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &app->path,
386 static DBusMessage *manager_destroy_application(DBusConnection *conn,
387 DBusMessage *msg, void *user_data)
390 struct hdp_application *app;
393 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
395 return btd_error_invalid_args(msg);
397 l = g_slist_find_custom(applications, path, cmp_app);
400 return g_dbus_create_error(msg,
401 ERROR_INTERFACE ".InvalidArguments",
402 "Invalid arguments in method call, "
403 "no such application");
406 applications = g_slist_remove(applications, app);
408 remove_application(app);
410 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
413 static void manager_path_unregister(gpointer data)
415 g_slist_foreach(applications, (GFunc) hdp_application_unref, NULL);
417 g_slist_free(applications);
420 g_slist_foreach(adapters, (GFunc) update_adapter, NULL);
423 static const GDBusMethodTable health_manager_methods[] = {
424 { GDBUS_METHOD("CreateApplication",
425 GDBUS_ARGS({ "config", "a{sv}" }),
426 GDBUS_ARGS({ "application", "o" }),
427 manager_create_application) },
428 { GDBUS_METHOD("DestroyApplication",
429 GDBUS_ARGS({ "application", "o" }), NULL,
430 manager_destroy_application) },
434 static DBusMessage *channel_get_properties(DBusConnection *conn,
435 DBusMessage *msg, void *user_data)
437 struct hdp_channel *chan = user_data;
438 DBusMessageIter iter, dict;
443 reply = dbus_message_new_method_return(msg);
447 dbus_message_iter_init_append(reply, &iter);
449 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
450 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
451 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
452 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
454 path = device_get_path(chan->dev->dev);
455 dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH, &path);
457 path = chan->app->path;
458 dict_append_entry(&dict, "Application", DBUS_TYPE_OBJECT_PATH, &path);
460 if (chan->config == HDP_RELIABLE_DC)
461 type = g_strdup("Reliable");
463 type = g_strdup("Streaming");
465 dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &type);
469 dbus_message_iter_close_container(&iter, &dict);
474 static void hdp_tmp_dc_data_destroy(gpointer data)
476 struct hdp_tmp_dc_data *hdp_conn = data;
478 hdp_tmp_dc_data_unref(hdp_conn);
481 static void abort_mdl_cb(GError *err, gpointer data)
484 error("Aborting error: %s", err->message);
487 static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
489 struct hdp_tmp_dc_data *dc_data = data;
494 struct hdp_channel *chan = dc_data->hdp_chann;
497 error("%s", err->message);
498 reply = g_dbus_create_error(dc_data->msg,
499 ERROR_INTERFACE ".HealthError",
500 "Cannot reconnect: %s", err->message);
501 g_dbus_send_message(dc_data->conn, reply);
503 /* Send abort request because remote side */
504 /* is now in PENDING state */
505 if (!mcap_mdl_abort(chan->mdl, abort_mdl_cb, NULL, NULL,
507 error("%s", gerr->message);
513 fd = mcap_mdl_get_fd(dc_data->hdp_chann->mdl);
515 reply = g_dbus_create_error(dc_data->msg,
516 ERROR_INTERFACE ".HealthError",
517 "Cannot get file descriptor");
518 g_dbus_send_message(dc_data->conn, reply);
522 reply = g_dbus_create_reply(dc_data->msg, DBUS_TYPE_UNIX_FD,
523 &fd, DBUS_TYPE_INVALID);
524 g_dbus_send_message(dc_data->conn, reply);
526 g_dbus_emit_signal(dc_data->conn,
527 device_get_path(dc_data->hdp_chann->dev->dev),
528 HEALTH_DEVICE, "ChannelConnected",
529 DBUS_TYPE_OBJECT_PATH, &dc_data->hdp_chann->path,
533 static void hdp_get_dcpsm_cb(uint16_t dcpsm, gpointer user_data, GError *err)
535 struct hdp_tmp_dc_data *hdp_conn = user_data;
536 struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
541 hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
545 if (hdp_chann->config == HDP_RELIABLE_DC)
546 mode = L2CAP_MODE_ERTM;
548 mode = L2CAP_MODE_STREAMING;
550 if (mcap_connect_mdl(hdp_chann->mdl, mode, dcpsm, hdp_conn->cb,
551 hdp_tmp_dc_data_ref(hdp_conn),
552 hdp_tmp_dc_data_destroy, &gerr))
554 #ifdef __TIZEN_PATCH__
555 hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
557 hdp_tmp_dc_data_unref(hdp_conn);
559 hdp_tmp_dc_data_unref(hdp_conn);
560 hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
565 static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
568 struct hdp_tmp_dc_data *dc_data = data;
573 reply = g_dbus_create_error(dc_data->msg,
574 ERROR_INTERFACE ".HealthError",
575 "Cannot reconnect: %s", err->message);
576 g_dbus_send_message(dc_data->conn, reply);
580 dc_data->cb = hdp_mdl_reconn_cb;
582 if (hdp_get_dcpsm(dc_data->hdp_chann->dev, hdp_get_dcpsm_cb,
583 hdp_tmp_dc_data_ref(dc_data),
584 hdp_tmp_dc_data_destroy, &gerr))
587 error("%s", gerr->message);
589 reply = g_dbus_create_error(dc_data->msg,
590 ERROR_INTERFACE ".HealthError",
591 "Cannot reconnect: %s", gerr->message);
592 g_dbus_send_message(dc_data->conn, reply);
593 hdp_tmp_dc_data_unref(dc_data);
596 /* Send abort request because remote side is now in PENDING state */
597 if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) {
598 error("%s", gerr->message);
603 static DBusMessage *channel_acquire_continue(struct hdp_tmp_dc_data *data,
611 return g_dbus_create_error(data->msg,
612 ERROR_INTERFACE ".HealthError",
616 fd = mcap_mdl_get_fd(data->hdp_chann->mdl);
618 return g_dbus_create_reply(data->msg, DBUS_TYPE_UNIX_FD, &fd,
621 hdp_tmp_dc_data_ref(data);
622 if (mcap_reconnect_mdl(data->hdp_chann->mdl, device_reconnect_mdl_cb,
623 data, hdp_tmp_dc_data_destroy, &gerr))
625 #ifdef __TIZEN_PATCH__
626 reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
627 "Cannot reconnect: %s", gerr->message);
629 hdp_tmp_dc_data_unref(data);
631 hdp_tmp_dc_data_unref(data);
632 reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
633 "Cannot reconnect: %s", gerr->message);
640 static void channel_acquire_cb(gpointer data, GError *err)
642 struct hdp_tmp_dc_data *dc_data = data;
645 reply = channel_acquire_continue(data, err);
648 g_dbus_send_message(dc_data->conn, reply);
651 static DBusMessage *channel_acquire(DBusConnection *conn,
652 DBusMessage *msg, void *user_data)
654 struct hdp_channel *chan = user_data;
655 struct hdp_tmp_dc_data *dc_data;
659 dc_data = g_new0(struct hdp_tmp_dc_data, 1);
660 dc_data->conn = dbus_connection_ref(conn);
661 dc_data->msg = dbus_message_ref(msg);
662 dc_data->hdp_chann = hdp_channel_ref(chan);
664 if (chan->dev->mcl_conn) {
665 reply = channel_acquire_continue(hdp_tmp_dc_data_ref(dc_data),
667 hdp_tmp_dc_data_unref(dc_data);
671 if (hdp_establish_mcl(chan->dev, channel_acquire_cb,
672 hdp_tmp_dc_data_ref(dc_data),
673 hdp_tmp_dc_data_destroy, &gerr))
676 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
677 "%s", gerr->message);
678 hdp_tmp_dc_data_unref(dc_data);
684 static void close_mdl(struct hdp_channel *hdp_chann)
688 fd = mcap_mdl_get_fd(hdp_chann->mdl);
695 static DBusMessage *channel_release(DBusConnection *conn,
696 DBusMessage *msg, void *user_data)
698 struct hdp_channel *hdp_chann = user_data;
700 close_mdl(hdp_chann);
702 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
705 static void free_echo_data(struct hdp_echo_data *edata)
711 g_source_remove(edata->tid);
713 if (edata->buf != NULL)
720 static void health_channel_destroy(void *data)
722 struct hdp_channel *hdp_chan = data;
723 struct hdp_device *dev = hdp_chan->dev;
725 DBG("Destroy Health Channel %s", hdp_chan->path);
726 if (g_slist_find(dev->channels, hdp_chan) == NULL)
729 dev->channels = g_slist_remove(dev->channels, hdp_chan);
731 if (hdp_chan->mdep != HDP_MDEP_ECHO)
732 g_dbus_emit_signal(dev->conn, device_get_path(dev->dev),
733 HEALTH_DEVICE, "ChannelDeleted",
734 DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
737 if (hdp_chan == dev->fr) {
738 hdp_channel_unref(dev->fr);
743 hdp_channel_unref(hdp_chan);
746 static const GDBusMethodTable health_channels_methods[] = {
747 { GDBUS_METHOD("GetProperties",
748 NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
749 channel_get_properties) },
750 { GDBUS_ASYNC_METHOD("Acquire",
751 NULL, GDBUS_ARGS({ "fd", "h" }),
753 { GDBUS_METHOD("Release", NULL, NULL, channel_release) },
757 static struct hdp_channel *create_channel(struct hdp_device *dev,
759 struct mcap_mdl *mdl,
761 struct hdp_application *app,
764 struct hdp_channel *hdp_chann;
769 hdp_chann = g_new0(struct hdp_channel, 1);
770 hdp_chann->config = config;
771 hdp_chann->dev = health_device_ref(dev);
772 hdp_chann->mdlid = mdlid;
775 hdp_chann->mdl = mcap_mdl_ref(mdl);
778 hdp_chann->mdep = app->id;
779 hdp_chann->app = hdp_application_ref(app);
781 hdp_chann->edata = g_new0(struct hdp_echo_data, 1);
783 hdp_chann->path = g_strdup_printf("%s/chan%d",
784 device_get_path(hdp_chann->dev->dev),
787 dev->channels = g_slist_append(dev->channels,
788 hdp_channel_ref(hdp_chann));
790 if (hdp_chann->mdep == HDP_MDEP_ECHO)
791 return hdp_channel_ref(hdp_chann);
793 if (!g_dbus_register_interface(dev->conn, hdp_chann->path,
795 health_channels_methods, NULL, NULL,
796 hdp_chann, health_channel_destroy)) {
797 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
798 "Can't register the channel interface");
799 health_channel_destroy(hdp_chann);
803 return hdp_channel_ref(hdp_chann);
806 static void remove_channels(struct hdp_device *dev)
808 struct hdp_channel *chan;
811 while (dev->channels != NULL) {
812 chan = dev->channels->data;
814 path = g_strdup(chan->path);
815 if (!g_dbus_unregister_interface(dev->conn, path,
817 health_channel_destroy(chan);
822 static void close_device_con(struct hdp_device *dev, gboolean cache)
824 if (dev->mcl == NULL)
827 mcap_close_mcl(dev->mcl, cache);
828 dev->mcl_conn = FALSE;
833 device_unref_mcl(dev);
834 remove_channels(dev);
836 if (!dev->sdp_present) {
839 path = device_get_path(dev->dev);
840 g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE);
844 static int send_echo_data(int sock, const void *buf, uint32_t size)
846 const uint8_t *buf_b = buf;
849 while (sent < size) {
850 int n = write(sock, buf_b + sent, size - sent);
859 static gboolean serve_echo(GIOChannel *io_chan, GIOCondition cond,
862 struct hdp_channel *chan = data;
863 uint8_t buf[MCAP_DC_MTU];
866 if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
867 hdp_channel_unref(chan);
871 if (chan->edata->echo_done)
874 chan->edata->echo_done = TRUE;
876 fd = g_io_channel_unix_get_fd(io_chan);
877 len = read(fd, buf, sizeof(buf));
879 if (send_echo_data(fd, buf, len) >= 0)
883 close_device_con(chan->dev, FALSE);
884 hdp_channel_unref(chan);
888 static gboolean check_channel_conf(struct hdp_channel *chan)
896 fd = mcap_mdl_get_fd(chan->mdl);
899 io = g_io_channel_unix_new(fd);
901 if (!bt_io_get(io, BT_IO_L2CAP, &err,
902 BT_IO_OPT_MODE, &mode,
903 BT_IO_OPT_IMTU, &imtu,
904 BT_IO_OPT_OMTU, &omtu,
905 BT_IO_OPT_INVALID)) {
906 error("Error: %s", err->message);
907 g_io_channel_unref(io);
912 g_io_channel_unref(io);
914 switch (chan->config) {
915 case HDP_RELIABLE_DC:
916 if (mode != L2CAP_MODE_ERTM)
919 case HDP_STREAMING_DC:
920 if (mode != L2CAP_MODE_STREAMING)
924 error("Error: Connected with unknown configuration");
928 DBG("MDL imtu %d omtu %d Channel imtu %d omtu %d", imtu, omtu,
929 chan->imtu, chan->omtu);
936 if (chan->imtu != imtu || chan->omtu != omtu)
942 static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
944 struct hdp_device *dev = data;
945 struct hdp_channel *chan;
947 DBG("hdp_mcap_mdl_connected_cb");
948 if (dev->ndc == NULL)
952 if (chan->mdl == NULL)
953 chan->mdl = mcap_mdl_ref(mdl);
955 if (g_slist_find(dev->channels, chan) == NULL)
956 dev->channels = g_slist_prepend(dev->channels,
957 hdp_channel_ref(chan));
959 if (!check_channel_conf(chan)) {
964 if (chan->mdep == HDP_MDEP_ECHO) {
968 fd = mcap_mdl_get_fd(chan->mdl);
972 chan->edata->echo_done = FALSE;
973 io = g_io_channel_unix_new(fd);
974 g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
975 serve_echo, hdp_channel_ref(chan));
976 g_io_channel_unref(io);
980 g_dbus_emit_signal(dev->conn, device_get_path(dev->dev), HEALTH_DEVICE,
982 DBUS_TYPE_OBJECT_PATH, &chan->path,
988 dev->fr = hdp_channel_ref(chan);
990 emit_property_changed(dev->conn, device_get_path(dev->dev),
991 HEALTH_DEVICE, "MainChannel",
992 DBUS_TYPE_OBJECT_PATH, &dev->fr->path);
995 hdp_channel_unref(dev->ndc);
999 static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
1001 /* struct hdp_device *dev = data; */
1003 DBG("hdp_mcap_mdl_closed_cb");
1008 static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
1010 struct hdp_device *dev = data;
1011 struct hdp_channel *chan;
1015 DBG("hdp_mcap_mdl_deleted_cb");
1016 l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1022 path = g_strdup(chan->path);
1023 if (!g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL))
1024 health_channel_destroy(chan);
1028 static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
1030 struct hdp_device *dev = data;
1032 DBG("hdp_mcap_mdl_aborted_cb");
1033 if (dev->ndc == NULL)
1036 dev->ndc->mdl = mcap_mdl_ref(mdl);
1038 if (g_slist_find(dev->channels, dev->ndc) == NULL)
1039 dev->channels = g_slist_prepend(dev->channels,
1040 hdp_channel_ref(dev->ndc));
1042 if (dev->ndc->mdep != HDP_MDEP_ECHO)
1043 g_dbus_emit_signal(dev->conn, device_get_path(dev->dev),
1044 HEALTH_DEVICE, "ChannelConnected",
1045 DBUS_TYPE_OBJECT_PATH, &dev->ndc->path,
1048 hdp_channel_unref(dev->ndc);
1052 static uint8_t hdp2l2cap_mode(uint8_t hdp_mode)
1054 return hdp_mode == HDP_STREAMING_DC ? L2CAP_MODE_STREAMING :
1058 static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
1059 uint16_t mdlid, uint8_t *conf, void *data)
1061 struct hdp_device *dev = data;
1062 struct hdp_application *app;
1066 DBG("Data channel request");
1068 if (mdepid == HDP_MDEP_ECHO) {
1070 case HDP_NO_PREFERENCE_DC:
1071 *conf = HDP_RELIABLE_DC;
1072 case HDP_RELIABLE_DC:
1074 case HDP_STREAMING_DC:
1075 return MCAP_CONFIGURATION_REJECTED;
1077 /* Special case defined in HDP spec 3.4. When an invalid
1078 * configuration is received we shall close the MCL when
1079 * we are still processing the callback. */
1080 close_device_con(dev, FALSE);
1081 return MCAP_CONFIGURATION_REJECTED; /* not processed */
1084 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1085 L2CAP_MODE_ERTM, &err)) {
1086 error("Error: %s", err->message);
1088 return MCAP_MDL_BUSY;
1091 dev->ndc = create_channel(dev, *conf, NULL, mdlid, NULL, NULL);
1092 if (dev->ndc == NULL)
1093 return MCAP_MDL_BUSY;
1095 return MCAP_SUCCESS;
1098 l = g_slist_find_custom(applications, &mdepid, cmp_app_id);
1100 return MCAP_INVALID_MDEP;
1104 /* Check if is the first dc if so,
1105 * only reliable configuration is allowed */
1107 case HDP_NO_PREFERENCE_DC:
1108 if (app->role == HDP_SINK)
1109 return MCAP_CONFIGURATION_REJECTED;
1110 else if (dev->fr && app->chan_type_set)
1111 *conf = app->chan_type;
1113 *conf = HDP_RELIABLE_DC;
1115 case HDP_STREAMING_DC:
1116 if (!dev->fr || app->role == HDP_SOURCE)
1117 return MCAP_CONFIGURATION_REJECTED;
1118 case HDP_RELIABLE_DC:
1119 if (app->role == HDP_SOURCE)
1120 return MCAP_CONFIGURATION_REJECTED;
1123 /* Special case defined in HDP spec 3.4. When an invalid
1124 * configuration is received we shall close the MCL when
1125 * we are still processing the callback. */
1126 close_device_con(dev, FALSE);
1127 return MCAP_CONFIGURATION_REJECTED; /* not processed */
1130 l = g_slist_find_custom(dev->channels, &mdlid, cmp_chan_mdlid);
1132 struct hdp_channel *chan = l->data;
1135 path = g_strdup(chan->path);
1136 g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL);
1140 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1141 hdp2l2cap_mode(*conf), &err)) {
1142 error("Error: %s", err->message);
1144 return MCAP_MDL_BUSY;
1147 dev->ndc = create_channel(dev, *conf, NULL, mdlid, app, NULL);
1148 if (dev->ndc == NULL)
1149 return MCAP_MDL_BUSY;
1151 return MCAP_SUCCESS;
1154 static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
1156 struct hdp_device *dev = data;
1157 struct hdp_channel *chan;
1161 l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1163 return MCAP_INVALID_MDL;
1167 if (dev->fr == NULL && chan->config != HDP_RELIABLE_DC &&
1168 chan->mdep != HDP_MDEP_ECHO)
1169 return MCAP_UNSPECIFIED_ERROR;
1171 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1172 hdp2l2cap_mode(chan->config), &err)) {
1173 error("Error: %s", err->message);
1175 return MCAP_MDL_BUSY;
1178 dev->ndc = hdp_channel_ref(chan);
1180 return MCAP_SUCCESS;
1183 gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err)
1187 if (device->mcl == NULL)
1190 ret = mcap_mcl_set_cb(device->mcl, device, err,
1191 MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
1192 MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
1193 MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
1194 MCAP_MDL_CB_ABORTED, hdp_mcap_mdl_aborted_cb,
1195 MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
1196 MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
1197 MCAP_MDL_CB_INVALID);
1202 error("Can't set mcl callbacks, closing mcl");
1203 close_device_con(device, TRUE);
1208 static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
1210 struct hdp_device *hdp_device;
1214 mcap_mcl_get_addr(mcl, &addr);
1215 l = g_slist_find_custom(devices, &addr, cmp_dev_addr);
1217 struct hdp_adapter *hdp_adapter = data;
1218 struct btd_device *device;
1222 device = adapter_get_device(connection,
1223 hdp_adapter->btd_adapter, str);
1226 hdp_device = create_health_device(connection, device);
1229 devices = g_slist_append(devices, hdp_device);
1231 hdp_device = l->data;
1233 hdp_device->mcl = mcap_mcl_ref(mcl);
1234 hdp_device->mcl_conn = TRUE;
1236 DBG("New mcl connected from %s", device_get_path(hdp_device->dev));
1238 hdp_set_mcl_cb(hdp_device, NULL);
1241 static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
1243 struct hdp_device *hdp_device;
1246 l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1250 hdp_device = l->data;
1251 hdp_device->mcl_conn = TRUE;
1253 DBG("MCL reconnected %s", device_get_path(hdp_device->dev));
1255 hdp_set_mcl_cb(hdp_device, NULL);
1258 static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
1260 struct hdp_device *hdp_device;
1263 l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1267 hdp_device = l->data;
1268 hdp_device->mcl_conn = FALSE;
1270 DBG("Mcl disconnected %s", device_get_path(hdp_device->dev));
1273 static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
1275 struct hdp_device *hdp_device;
1279 l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1283 hdp_device = l->data;
1284 device_unref_mcl(hdp_device);
1286 if (hdp_device->sdp_present)
1289 /* Because remote device hasn't announced an HDP record */
1290 /* the Bluetooth daemon won't notify when the device shall */
1291 /* be removed. Then we have to remove the HealthDevice */
1292 /* interface manually */
1293 path = device_get_path(hdp_device->dev);
1294 g_dbus_unregister_interface(hdp_device->conn, path, HEALTH_DEVICE);
1295 DBG("Mcl uncached %s", path);
1298 static void check_devices_mcl(void)
1300 struct hdp_device *dev;
1301 GSList *l, *to_delete = NULL;
1303 for (l = devices; l; l = l->next) {
1305 device_unref_mcl(dev);
1307 if (!dev->sdp_present)
1308 to_delete = g_slist_append(to_delete, dev);
1310 remove_channels(dev);
1313 for (l = to_delete; l; l = l->next) {
1316 path = device_get_path(dev->dev);
1317 g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE);
1320 g_slist_free(to_delete);
1323 static void release_adapter_instance(struct hdp_adapter *hdp_adapter)
1325 if (hdp_adapter->mi == NULL)
1328 check_devices_mcl();
1329 mcap_release_instance(hdp_adapter->mi);
1330 mcap_instance_unref(hdp_adapter->mi);
1331 hdp_adapter->mi = NULL;
1334 static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
1339 if (applications == NULL) {
1340 release_adapter_instance(hdp_adapter);
1344 if (hdp_adapter->mi != NULL)
1347 adapter_get_address(hdp_adapter->btd_adapter, &addr);
1348 hdp_adapter->mi = mcap_create_instance(&addr, BT_IO_SEC_MEDIUM, 0, 0,
1349 mcl_connected, mcl_reconnected,
1350 mcl_disconnected, mcl_uncached,
1351 NULL, /* CSP is not used by now */
1354 if (hdp_adapter->mi == NULL) {
1355 error("Error creating the MCAP instance: %s", err->message);
1360 hdp_adapter->ccpsm = mcap_get_ctrl_psm(hdp_adapter->mi, &err);
1362 error("Error getting MCAP control PSM: %s", err->message);
1366 hdp_adapter->dcpsm = mcap_get_data_psm(hdp_adapter->mi, &err);
1368 error("Error getting MCAP data PSM: %s", err->message);
1373 if (hdp_update_sdp_record(hdp_adapter, applications))
1375 error("Error updating the SDP record");
1378 release_adapter_instance(hdp_adapter);
1385 int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *adapter)
1387 struct hdp_adapter *hdp_adapter;
1389 hdp_adapter = g_new0(struct hdp_adapter, 1);
1390 hdp_adapter->btd_adapter = btd_adapter_ref(adapter);
1392 if(!update_adapter(hdp_adapter))
1395 adapters = g_slist_append(adapters, hdp_adapter);
1400 btd_adapter_unref(hdp_adapter->btd_adapter);
1401 g_free(hdp_adapter);
1405 void hdp_adapter_unregister(struct btd_adapter *adapter)
1407 struct hdp_adapter *hdp_adapter;
1410 l = g_slist_find_custom(adapters, adapter, cmp_adapter);
1415 hdp_adapter = l->data;
1416 adapters = g_slist_remove(adapters, hdp_adapter);
1417 if (hdp_adapter->sdp_handler > 0)
1418 remove_record_from_server(hdp_adapter->sdp_handler);
1419 release_adapter_instance(hdp_adapter);
1420 btd_adapter_unref(hdp_adapter->btd_adapter);
1421 g_free(hdp_adapter);
1424 static void delete_echo_channel_cb(GError *err, gpointer chan)
1426 if (err != NULL && err->code != MCAP_INVALID_MDL) {
1427 /* TODO: Decide if more action is required here */
1428 error("Error deleting echo channel: %s", err->message);
1432 health_channel_destroy(chan);
1435 static void delete_echo_channel(struct hdp_channel *chan)
1439 if (!chan->dev->mcl_conn) {
1440 error("Echo channel cannot be deleted: mcl closed");
1444 if (mcap_delete_mdl(chan->mdl, delete_echo_channel_cb,
1445 hdp_channel_ref(chan),
1446 (GDestroyNotify) hdp_channel_unref, &err))
1449 hdp_channel_unref(chan);
1450 error("Error deleting the echo channel: %s", err->message);
1453 /* TODO: Decide if more action is required here */
1456 static void abort_echo_channel_cb(GError *err, gpointer data)
1458 struct hdp_channel *chan = data;
1460 if (err != NULL && err->code != MCAP_ERROR_INVALID_OPERATION) {
1461 error("Aborting error: %s", err->message);
1462 if (err->code == MCAP_INVALID_MDL) {
1463 /* MDL is removed from MCAP so we can */
1464 /* free the data channel without sending */
1465 /* a MD_DELETE_MDL_REQ */
1466 /* TODO review the above comment */
1467 /* hdp_channel_unref(chan); */
1472 delete_echo_channel(chan);
1475 static void destroy_create_dc_data(gpointer data)
1477 struct hdp_create_dc *dc_data = data;
1479 hdp_create_data_unref(dc_data);
1482 static void *generate_echo_packet(void)
1487 buf = g_malloc(HDP_ECHO_LEN);
1490 for(i = 0; i < HDP_ECHO_LEN; i++)
1491 buf[i] = rand() % UINT8_MAX;
1496 static gboolean check_echo(GIOChannel *io_chan, GIOCondition cond,
1499 struct hdp_tmp_dc_data *hdp_conn = data;
1500 struct hdp_echo_data *edata = hdp_conn->hdp_chann->edata;
1501 struct hdp_channel *chan = hdp_conn->hdp_chann;
1502 uint8_t buf[MCAP_DC_MTU];
1507 if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
1512 fd = g_io_channel_unix_get_fd(io_chan);
1513 len = read(fd, buf, sizeof(buf));
1515 if (len != HDP_ECHO_LEN) {
1520 value = (memcmp(buf, edata->buf, len) == 0);
1523 reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_BOOLEAN, &value,
1525 g_dbus_send_message(hdp_conn->conn, reply);
1526 g_source_remove(edata->tid);
1532 close_device_con(chan->dev, FALSE);
1534 delete_echo_channel(chan);
1535 hdp_tmp_dc_data_unref(hdp_conn);
1540 static gboolean echo_timeout(gpointer data)
1542 struct hdp_channel *chan = data;
1546 error("Error: Echo request timeout");
1547 chan->edata->tid = 0;
1549 fd = mcap_mdl_get_fd(chan->mdl);
1553 io = g_io_channel_unix_new(fd);
1554 g_io_channel_shutdown(io, TRUE, NULL);
1559 static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
1562 struct hdp_tmp_dc_data *hdp_conn = data;
1563 struct hdp_echo_data *edata;
1564 GError *gerr = NULL;
1570 reply = g_dbus_create_error(hdp_conn->msg,
1571 ERROR_INTERFACE ".HealthError",
1572 "%s", err->message);
1573 g_dbus_send_message(hdp_conn->conn, reply);
1575 /* Send abort request because remote */
1576 /* side is now in PENDING state. */
1577 if (!mcap_mdl_abort(hdp_conn->hdp_chann->mdl,
1578 abort_echo_channel_cb,
1579 hdp_channel_ref(hdp_conn->hdp_chann),
1580 (GDestroyNotify) hdp_channel_unref,
1582 error("%s", gerr->message);
1584 hdp_channel_unref(hdp_conn->hdp_chann);
1589 fd = mcap_mdl_get_fd(hdp_conn->hdp_chann->mdl);
1591 reply = g_dbus_create_error(hdp_conn->msg,
1592 ERROR_INTERFACE ".HealthError",
1593 "Can't write in echo channel");
1594 g_dbus_send_message(hdp_conn->conn, reply);
1595 delete_echo_channel(hdp_conn->hdp_chann);
1599 edata = hdp_conn->hdp_chann->edata;
1600 edata->buf = generate_echo_packet();
1601 send_echo_data(fd, edata->buf, HDP_ECHO_LEN);
1603 io = g_io_channel_unix_new(fd);
1604 g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
1605 check_echo, hdp_tmp_dc_data_ref(hdp_conn));
1607 edata->tid = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
1608 ECHO_TIMEOUT, echo_timeout,
1609 hdp_channel_ref(hdp_conn->hdp_chann),
1610 (GDestroyNotify) hdp_channel_unref);
1612 g_io_channel_unref(io);
1615 static void delete_mdl_cb(GError *err, gpointer data)
1618 error("Deleting error: %s", err->message);
1621 static void abort_and_del_mdl_cb(GError *err, gpointer data)
1623 struct mcap_mdl *mdl = data;
1624 GError *gerr = NULL;
1627 error("%s", err->message);
1628 if (err->code == MCAP_INVALID_MDL) {
1629 /* MDL is removed from MCAP so we don't */
1630 /* need to delete it. */
1635 if (!mcap_delete_mdl(mdl, delete_mdl_cb, NULL, NULL, &gerr)) {
1636 error("%s", gerr->message);
1641 static void abort_mdl_connection_cb(GError *err, gpointer data)
1643 struct hdp_tmp_dc_data *hdp_conn = data;
1644 struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1647 error("Aborting error: %s", err->message);
1649 /* Connection operation has failed but we have to */
1650 /* notify the channel created at MCAP level */
1651 if (hdp_chann->mdep != HDP_MDEP_ECHO)
1652 g_dbus_emit_signal(hdp_conn->conn,
1653 device_get_path(hdp_chann->dev->dev),
1656 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1660 static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
1662 struct hdp_tmp_dc_data *hdp_conn = data;
1663 struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1664 struct hdp_device *dev = hdp_chann->dev;
1666 GError *gerr = NULL;
1669 error("%s", err->message);
1670 reply = g_dbus_create_reply(hdp_conn->msg,
1671 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1673 g_dbus_send_message(hdp_conn->conn, reply);
1675 /* Send abort request because remote side */
1676 /* is now in PENDING state */
1677 if (!mcap_mdl_abort(hdp_chann->mdl, abort_mdl_connection_cb,
1678 hdp_tmp_dc_data_ref(hdp_conn),
1679 hdp_tmp_dc_data_destroy, &gerr)) {
1680 hdp_tmp_dc_data_unref(hdp_conn);
1681 error("%s", gerr->message);
1687 reply = g_dbus_create_reply(hdp_conn->msg,
1688 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1690 g_dbus_send_message(hdp_conn->conn, reply);
1692 g_dbus_emit_signal(hdp_conn->conn,
1693 device_get_path(hdp_chann->dev->dev),
1696 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1699 if (!check_channel_conf(hdp_chann)) {
1700 close_mdl(hdp_chann);
1704 if (dev->fr != NULL)
1707 dev->fr = hdp_channel_ref(hdp_chann);
1709 emit_property_changed(dev->conn, device_get_path(dev->dev),
1710 HEALTH_DEVICE, "MainChannel",
1711 DBUS_TYPE_OBJECT_PATH, &dev->fr->path);
1714 static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
1715 GError *err, gpointer data)
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(user_data->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->conn = dbus_connection_ref(user_data->conn);
1756 hdp_conn->hdp_chann = hdp_chan;
1757 hdp_conn->cb = user_data->cb;
1758 hdp_chan->mdep = user_data->mdep;
1760 if (hdp_get_dcpsm(hdp_chan->dev, hdp_get_dcpsm_cb,
1761 hdp_tmp_dc_data_ref(hdp_conn),
1762 hdp_tmp_dc_data_destroy, &gerr))
1765 error("%s", gerr->message);
1768 reply = g_dbus_create_reply(hdp_conn->msg,
1769 DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
1771 g_dbus_send_message(hdp_conn->conn, reply);
1772 hdp_tmp_dc_data_unref(hdp_conn);
1774 /* Send abort request because remote side is now in PENDING state */
1775 if (!mcap_mdl_abort(hdp_chan->mdl, abort_mdl_connection_cb,
1776 hdp_tmp_dc_data_ref(hdp_conn),
1777 hdp_tmp_dc_data_destroy, &gerr)) {
1778 hdp_tmp_dc_data_unref(hdp_conn);
1779 error("%s", gerr->message);
1786 reply = g_dbus_create_error(user_data->msg,
1787 ERROR_INTERFACE ".HealthError",
1788 "%s", gerr->message);
1789 g_dbus_send_message(user_data->conn, reply);
1792 /* Send abort request because remote side is now in PENDING */
1793 /* state. Then we have to delete it because we couldn't */
1794 /* register the HealthChannel interface */
1795 if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl),
1796 (GDestroyNotify) mcap_mdl_unref, &gerr)) {
1797 error("%s", gerr->message);
1799 mcap_mdl_unref(mdl);
1803 static void device_create_dc_cb(gpointer user_data, GError *err)
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(data->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(data->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->conn = dbus_connection_ref(conn);
1852 data->cb = hdp_echo_connect_cb;
1853 hdp_create_data_ref(data);
1855 if (device->mcl_conn && device->mcl != NULL) {
1856 if (mcap_create_mdl(device->mcl, data->mdep, data->config,
1857 device_create_mdl_cb, data,
1858 destroy_create_dc_data, &err))
1863 if (hdp_establish_mcl(data->dev, device_create_dc_cb,
1864 data, destroy_create_dc_data, &err))
1868 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1869 "%s", err->message);
1871 hdp_create_data_unref(data);
1875 static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
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(user_data->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(user_data->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->conn = dbus_connection_ref(conn);
1957 data->cb = hdp_mdl_conn_cb;
1959 if (hdp_get_mdep(device, l->data, device_get_mdep_cb,
1960 hdp_create_data_ref(data),
1961 destroy_create_dc_data, &err))
1964 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1965 "%s", err->message);
1967 hdp_create_data_unref(data);
1971 static void hdp_mdl_delete_cb(GError *err, gpointer data)
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(del_data->conn, reply);
1985 path = g_strdup(del_data->hdp_chann->path);
1986 g_dbus_unregister_interface(del_data->conn, path, HEALTH_CHANNEL);
1989 reply = g_dbus_create_reply(del_data->msg, DBUS_TYPE_INVALID);
1990 g_dbus_send_message(del_data->conn, reply);
1993 static void hdp_continue_del_cb(gpointer user_data, GError *err)
1995 struct hdp_tmp_dc_data *del_data = user_data;
1996 GError *gerr = NULL;
2000 reply = g_dbus_create_error(del_data->msg,
2001 ERROR_INTERFACE ".HealthError",
2002 "%s", err->message);
2003 g_dbus_send_message(del_data->conn, reply);
2007 if (mcap_delete_mdl(del_data->hdp_chann->mdl, hdp_mdl_delete_cb,
2008 hdp_tmp_dc_data_ref(del_data),
2009 hdp_tmp_dc_data_destroy, &gerr))
2012 reply = g_dbus_create_error(del_data->msg,
2013 ERROR_INTERFACE ".HealthError",
2014 "%s", gerr->message);
2015 #ifdef __TIZEN_PATCH__
2016 g_dbus_send_message(del_data->conn, reply);
2018 hdp_tmp_dc_data_unref(del_data);
2020 hdp_tmp_dc_data_unref(del_data);
2022 g_dbus_send_message(del_data->conn, reply);
2026 static DBusMessage *device_destroy_channel(DBusConnection *conn,
2027 DBusMessage *msg, void *user_data)
2029 struct hdp_device *device = user_data;
2030 struct hdp_tmp_dc_data *del_data;
2031 struct hdp_channel *hdp_chan;
2037 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
2038 DBUS_TYPE_INVALID)){
2039 return btd_error_invalid_args(msg);
2042 l = g_slist_find_custom(device->channels, path, cmp_chan_path);
2044 return btd_error_invalid_args(msg);
2047 del_data = g_new0(struct hdp_tmp_dc_data, 1);
2048 del_data->msg = dbus_message_ref(msg);
2049 del_data->conn = dbus_connection_ref(conn);
2050 del_data->hdp_chann = hdp_channel_ref(hdp_chan);
2052 if (device->mcl_conn) {
2053 if (mcap_delete_mdl(hdp_chan->mdl, hdp_mdl_delete_cb,
2054 hdp_tmp_dc_data_ref(del_data),
2055 hdp_tmp_dc_data_destroy, &err))
2060 if (hdp_establish_mcl(device, hdp_continue_del_cb,
2061 hdp_tmp_dc_data_ref(del_data),
2062 hdp_tmp_dc_data_destroy, &err))
2066 reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
2067 "%s", err->message);
2068 hdp_tmp_dc_data_unref(del_data);
2073 static DBusMessage *device_get_properties(DBusConnection *conn,
2074 DBusMessage *msg, void *user_data)
2076 struct hdp_device *device = user_data;
2077 DBusMessageIter iter, dict;
2080 reply = dbus_message_new_method_return(msg);
2084 dbus_message_iter_init_append(reply, &iter);
2086 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
2087 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
2088 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
2089 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
2091 if (device->fr != NULL)
2092 dict_append_entry(&dict, "MainChannel", DBUS_TYPE_OBJECT_PATH,
2095 dbus_message_iter_close_container(&iter, &dict);
2100 static void health_device_destroy(void *data)
2102 struct hdp_device *device = data;
2104 DBG("Unregistered interface %s on path %s", HEALTH_DEVICE,
2105 device_get_path(device->dev));
2107 remove_channels(device);
2108 if (device->ndc != NULL) {
2109 hdp_channel_unref(device->ndc);
2113 devices = g_slist_remove(devices, device);
2114 health_device_unref(device);
2117 static const GDBusMethodTable health_device_methods[] = {
2118 { GDBUS_ASYNC_METHOD("Echo",
2119 NULL, GDBUS_ARGS({ "value", "b" }), device_echo) },
2120 { GDBUS_ASYNC_METHOD("CreateChannel",
2121 GDBUS_ARGS({ "application", "o" },
2122 { "configuration", "s" }),
2123 GDBUS_ARGS({ "channel", "o" }),
2124 device_create_channel) },
2125 { GDBUS_ASYNC_METHOD("DestroyChannel",
2126 GDBUS_ARGS({ "channel", "o" }), NULL,
2127 device_destroy_channel) },
2128 { GDBUS_METHOD("GetProperties",
2129 NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
2130 device_get_properties) },
2134 static const GDBusSignalTable health_device_signals[] = {
2135 { GDBUS_SIGNAL("ChannelConnected",
2136 GDBUS_ARGS({ "channel", "o" })) },
2137 { GDBUS_SIGNAL("ChannelDeleted",
2138 GDBUS_ARGS({ "channel", "o" })) },
2139 { GDBUS_SIGNAL("PropertyChanged",
2140 GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
2144 static struct hdp_device *create_health_device(DBusConnection *conn,
2145 struct btd_device *device)
2147 struct btd_adapter *adapter = device_get_adapter(device);
2148 const gchar *path = device_get_path(device);
2149 struct hdp_device *dev;
2155 dev = g_new0(struct hdp_device, 1);
2156 dev->conn = dbus_connection_ref(conn);
2157 dev->dev = btd_device_ref(device);
2158 health_device_ref(dev);
2160 l = g_slist_find_custom(adapters, adapter, cmp_adapter);
2164 dev->hdp_adapter = l->data;
2166 if (!g_dbus_register_interface(conn, path,
2168 health_device_methods,
2169 health_device_signals, NULL,
2170 dev, health_device_destroy)) {
2171 error("D-Bus failed to register %s interface", HEALTH_DEVICE);
2175 DBG("Registered interface %s on path %s", HEALTH_DEVICE, path);
2179 health_device_unref(dev);
2183 int hdp_device_register(DBusConnection *conn, struct btd_device *device)
2185 struct hdp_device *hdev;
2188 l = g_slist_find_custom(devices, device, cmp_device);
2191 hdev->sdp_present = TRUE;
2195 hdev = create_health_device(conn, device);
2199 hdev->sdp_present = TRUE;
2201 devices = g_slist_prepend(devices, hdev);
2205 void hdp_device_unregister(struct btd_device *device)
2207 struct hdp_device *hdp_dev;
2211 l = g_slist_find_custom(devices, device, cmp_device);
2216 path = device_get_path(hdp_dev->dev);
2217 g_dbus_unregister_interface(hdp_dev->conn, path, HEALTH_DEVICE);
2220 int hdp_manager_start(DBusConnection *conn)
2222 DBG("Starting Health manager");
2224 if (!g_dbus_register_interface(conn, MANAGER_PATH,
2226 health_manager_methods, NULL, NULL,
2227 NULL, manager_path_unregister)) {
2228 error("D-Bus failed to register %s interface", HEALTH_MANAGER);
2232 connection = dbus_connection_ref(conn);
2237 void hdp_manager_stop(void)
2239 g_dbus_unregister_interface(connection, MANAGER_PATH, HEALTH_MANAGER);
2241 dbus_connection_unref(connection);
2242 DBG("Stopped Health manager");
2245 struct hdp_device *health_device_ref(struct hdp_device *hdp_dev)
2249 DBG("health_device_ref(%p): ref=%d", hdp_dev, hdp_dev->ref);
2254 void health_device_unref(struct hdp_device *hdp_dev)
2258 DBG("health_device_unref(%p): ref=%d", hdp_dev, hdp_dev->ref);
2260 if (hdp_dev->ref > 0)
2263 free_health_device(hdp_dev);