profiles/health: Replace random number generation function
[platform/upstream/bluez.git] / profiles / health / hdp.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
7  *
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include <stdlib.h>
15 #include <stdint.h>
16 #include <stdbool.h>
17 #include <unistd.h>
18 #include <sys/random.h>
19
20 #include <glib.h>
21
22 #include "lib/bluetooth.h"
23 #include "lib/l2cap.h"
24 #include "lib/sdp.h"
25
26 #include "gdbus/gdbus.h"
27
28 #include "src/dbus-common.h"
29 #include "src/log.h"
30 #include "src/error.h"
31 #include "src/adapter.h"
32 #include "src/device.h"
33 #include "src/sdpd.h"
34 #include "src/shared/timeout.h"
35 #include "btio/btio.h"
36
37 #include "hdp_types.h"
38 #include "hdp_util.h"
39 #include "hdp.h"
40 #include "mcap.h"
41
42 #define ECHO_TIMEOUT    1 /* second */
43 #define HDP_ECHO_LEN    15
44
45 static GSList *applications = NULL;
46 static GSList *devices = NULL;
47 static uint8_t next_app_id = HDP_MDEP_INITIAL;
48
49 static GSList *adapters;
50
51 static struct hdp_device *create_health_device(struct btd_device *device);
52 static void free_echo_data(struct hdp_echo_data *edata);
53
54 struct hdp_create_dc {
55         DBusMessage                     *msg;
56         struct hdp_application          *app;
57         struct hdp_device               *dev;
58         uint8_t                         config;
59         uint8_t                         mdep;
60         guint                           ref;
61         mcap_mdl_operation_cb           cb;
62 };
63
64 struct hdp_tmp_dc_data {
65         DBusMessage                     *msg;
66         struct hdp_channel              *hdp_chann;
67         guint                           ref;
68         mcap_mdl_operation_cb           cb;
69 };
70
71 struct hdp_echo_data {
72         gboolean                echo_done;      /* Is a echo was already done */
73         gpointer                buf;            /* echo packet sent */
74         unsigned int            tid;            /* echo timeout */
75 };
76
77 static struct hdp_channel *hdp_channel_ref(struct hdp_channel *chan)
78 {
79         if (chan == NULL)
80                 return NULL;
81
82         chan->ref++;
83
84         DBG("(%p): ref=%d", chan, chan->ref);
85         return chan;
86 }
87
88 static void free_health_channel(struct hdp_channel *chan)
89 {
90         if (chan->mdep == HDP_MDEP_ECHO) {
91                 free_echo_data(chan->edata);
92                 chan->edata = NULL;
93         }
94
95         mcap_mdl_unref(chan->mdl);
96         hdp_application_unref(chan->app);
97         health_device_unref(chan->dev);
98         g_free(chan->path);
99         g_free(chan);
100 }
101
102 static void hdp_channel_unref(struct hdp_channel *chan)
103 {
104         if (chan == NULL)
105                 return;
106
107         chan->ref --;
108         DBG("(%p): ref=%d", chan, chan->ref);
109
110         if (chan->ref > 0)
111                 return;
112
113         free_health_channel(chan);
114 }
115
116 static void free_hdp_create_dc(struct hdp_create_dc *dc_data)
117 {
118         dbus_message_unref(dc_data->msg);
119         hdp_application_unref(dc_data->app);
120         health_device_unref(dc_data->dev);
121
122         g_free(dc_data);
123 }
124
125 static struct hdp_create_dc *hdp_create_data_ref(struct hdp_create_dc *dc_data)
126 {
127         dc_data->ref++;
128
129         DBG("(%p): ref=%d", dc_data, dc_data->ref);
130
131         return dc_data;
132 }
133
134 static void hdp_create_data_unref(struct hdp_create_dc *dc_data)
135 {
136         dc_data->ref--;
137
138         DBG("(%p): ref=%d", dc_data, dc_data->ref);
139
140         if (dc_data->ref > 0)
141                 return;
142
143         free_hdp_create_dc(dc_data);
144 }
145
146 static void free_hdp_conn_dc(struct hdp_tmp_dc_data *data)
147 {
148         dbus_message_unref(data->msg);
149         hdp_channel_unref(data->hdp_chann);
150
151         g_free(data);
152 }
153
154 static struct hdp_tmp_dc_data *hdp_tmp_dc_data_ref(struct hdp_tmp_dc_data *data)
155 {
156         data->ref++;
157
158         DBG("hdp_conn_data_ref(%p): ref=%d", data, data->ref);
159
160         return data;
161 }
162
163 static void hdp_tmp_dc_data_unref(struct hdp_tmp_dc_data *data)
164 {
165         data->ref--;
166
167         DBG("hdp_conn_data_unref(%p): ref=%d", data, data->ref);
168
169         if (data->ref > 0)
170                 return;
171
172         free_hdp_conn_dc(data);
173 }
174
175 static int cmp_app_id(gconstpointer a, gconstpointer b)
176 {
177         const struct hdp_application *app = a;
178         const uint8_t *id = b;
179
180         return app->id - *id;
181 }
182
183 static int cmp_adapter(gconstpointer a, gconstpointer b)
184 {
185         const struct hdp_adapter *hdp_adapter = a;
186         const struct btd_adapter *adapter = b;
187
188         if (hdp_adapter->btd_adapter == adapter)
189                 return 0;
190
191         return -1;
192 }
193
194 static int cmp_device(gconstpointer a, gconstpointer b)
195 {
196         const struct hdp_device *hdp_device = a;
197         const struct btd_device *device = b;
198
199         if (hdp_device->dev == device)
200                 return 0;
201
202         return -1;
203 }
204
205 static int cmp_dev_addr(gconstpointer a, gconstpointer dst)
206 {
207         const struct hdp_device *device = a;
208
209         return bacmp(device_get_address(device->dev), dst);
210 }
211
212 static int cmp_dev_mcl(gconstpointer a, gconstpointer mcl)
213 {
214         const struct hdp_device *device = a;
215
216         if (mcl == device->mcl)
217                 return 0;
218         return -1;
219 }
220
221 static int cmp_chan_mdlid(gconstpointer a, gconstpointer b)
222 {
223         const struct hdp_channel *chan = a;
224         const uint16_t *mdlid = b;
225
226         return chan->mdlid - *mdlid;
227 }
228
229 static int cmp_chan_path(gconstpointer a, gconstpointer b)
230 {
231         const struct hdp_channel *chan = a;
232         const char *path = b;
233
234         return g_ascii_strcasecmp(chan->path, path);
235 }
236
237 static int cmp_chan_mdl(gconstpointer a, gconstpointer mdl)
238 {
239         const struct hdp_channel *chan = a;
240
241         if (chan->mdl == mdl)
242                 return 0;
243         return -1;
244 }
245
246 static uint8_t get_app_id(void)
247 {
248         uint8_t id = next_app_id;
249
250         do {
251                 GSList *l = g_slist_find_custom(applications, &id, cmp_app_id);
252
253                 if (l == NULL) {
254                         next_app_id = (id % HDP_MDEP_FINAL) + 1;
255                         return id;
256                 } else
257                         id = (id % HDP_MDEP_FINAL) + 1;
258         } while (id != next_app_id);
259
260         /* No more ids available */
261         return 0;
262 }
263
264 static int cmp_app(gconstpointer a, gconstpointer b)
265 {
266         const struct hdp_application *app = a;
267
268         return g_strcmp0(app->path, b);
269 }
270
271 static gboolean set_app_path(struct hdp_application *app)
272 {
273         app->id = get_app_id();
274         if (app->id == 0)
275                 return FALSE;
276         app->path = g_strdup_printf(MANAGER_PATH "/health_app_%d", app->id);
277
278         return TRUE;
279 };
280
281 static void device_unref_mcl(struct hdp_device *hdp_device)
282 {
283         if (hdp_device->mcl == NULL)
284                 return;
285
286         mcap_close_mcl(hdp_device->mcl, FALSE);
287         mcap_mcl_unref(hdp_device->mcl);
288         hdp_device->mcl = NULL;
289         hdp_device->mcl_conn = FALSE;
290 }
291
292 static void free_health_device(struct hdp_device *device)
293 {
294         if (device->dev != NULL) {
295                 btd_device_unref(device->dev);
296                 device->dev = NULL;
297         }
298
299         device_unref_mcl(device);
300
301         g_free(device);
302 }
303
304 static void update_adapter_cb(void *data, void *user_data);
305
306 static void remove_application(struct hdp_application *app)
307 {
308         DBG("Application %s deleted", app->path);
309         hdp_application_unref(app);
310
311         g_slist_foreach(adapters, update_adapter_cb, NULL);
312 }
313
314 static void client_disconnected(DBusConnection *conn, void *user_data)
315 {
316         struct hdp_application *app = user_data;
317
318         DBG("Client disconnected from the bus, deleting hdp application");
319         applications = g_slist_remove(applications, app);
320
321         app->dbus_watcher = 0; /* Watcher shouldn't be freed in this case */
322         remove_application(app);
323 }
324
325 static DBusMessage *manager_create_application(DBusConnection *conn,
326                                         DBusMessage *msg, void *user_data)
327 {
328         struct hdp_application *app;
329         const char *name;
330         DBusMessageIter iter;
331         GError *err = NULL;
332
333         dbus_message_iter_init(msg, &iter);
334         app = hdp_get_app_config(&iter, &err);
335         if (err != NULL) {
336                 g_error_free(err);
337                 return btd_error_invalid_args(msg);
338         }
339
340         name = dbus_message_get_sender(msg);
341         if (name == NULL) {
342                 hdp_application_unref(app);
343                 return g_dbus_create_error(msg,
344                                         ERROR_INTERFACE ".HealthError",
345                                         "Can't get sender name");
346         }
347
348         if (!set_app_path(app)) {
349                 hdp_application_unref(app);
350                 return g_dbus_create_error(msg,
351                                 ERROR_INTERFACE ".HealthError",
352                                 "Can't get a valid id for the application");
353         }
354
355         app->oname = g_strdup(name);
356
357         applications = g_slist_prepend(applications, app);
358
359         app->dbus_watcher =
360                         g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
361                                         name, client_disconnected, app, NULL);
362         g_slist_foreach(adapters, update_adapter_cb, NULL);
363
364         DBG("Health application created with id %s", app->path);
365
366         return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &app->path,
367                                                         DBUS_TYPE_INVALID);
368 }
369
370 static DBusMessage *manager_destroy_application(DBusConnection *conn,
371                                         DBusMessage *msg, void *user_data)
372 {
373         const char *path;
374         struct hdp_application *app;
375         GSList *l;
376
377         if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
378                                                 DBUS_TYPE_INVALID))
379                 return btd_error_invalid_args(msg);
380
381         l = g_slist_find_custom(applications, path, cmp_app);
382
383         if (l == NULL)
384                 return g_dbus_create_error(msg,
385                                         ERROR_INTERFACE ".InvalidArguments",
386                                         "Invalid arguments in method call, "
387                                         "no such application");
388
389         app = l->data;
390         applications = g_slist_remove(applications, app);
391
392         remove_application(app);
393
394         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
395 }
396
397 static void application_unref(void *data, void *user_data)
398 {
399         hdp_application_unref(data);
400 }
401
402 static void manager_path_unregister(gpointer data)
403 {
404         g_slist_foreach(applications, application_unref, NULL);
405
406         g_slist_free(applications);
407         applications = NULL;
408
409         g_slist_foreach(adapters, update_adapter_cb, NULL);
410 }
411
412 static const GDBusMethodTable health_manager_methods[] = {
413         { GDBUS_METHOD("CreateApplication",
414                         GDBUS_ARGS({ "config", "a{sv}" }),
415                         GDBUS_ARGS({ "application", "o" }),
416                         manager_create_application) },
417         { GDBUS_METHOD("DestroyApplication",
418                         GDBUS_ARGS({ "application", "o" }), NULL,
419                         manager_destroy_application) },
420         { }
421 };
422
423 static gboolean channel_property_get_device(const GDBusPropertyTable *property,
424                                         DBusMessageIter *iter, void *data)
425 {
426         struct hdp_channel *chan = data;
427         const char *path = device_get_path(chan->dev->dev);
428
429         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
430
431         return TRUE;
432 }
433
434 static gboolean channel_property_get_application(
435                                         const GDBusPropertyTable *property,
436                                         DBusMessageIter *iter, void *data)
437 {
438         struct hdp_channel *chan = data;
439         const char *path = chan->app->path;
440
441         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
442
443         return TRUE;
444 }
445
446 static gboolean channel_property_get_type(const GDBusPropertyTable *property,
447                                         DBusMessageIter *iter, void *data)
448 {
449         struct hdp_channel *chan = data;
450         const char *type;
451
452         if (chan->config == HDP_RELIABLE_DC)
453                 type = "reliable";
454         else
455                 type = "streaming";
456
457         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &type);
458
459         return TRUE;
460 }
461
462 static void hdp_tmp_dc_data_destroy(gpointer data)
463 {
464         struct hdp_tmp_dc_data *hdp_conn = data;
465
466         hdp_tmp_dc_data_unref(hdp_conn);
467 }
468
469 static void abort_mdl_cb(GError *err, gpointer data)
470 {
471         if (err != NULL)
472                 error("Aborting error: %s", err->message);
473 }
474
475 static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
476 {
477         DBusConnection *conn = btd_get_dbus_connection();
478         struct hdp_tmp_dc_data *dc_data = data;
479         DBusMessage *reply;
480         int fd;
481
482         if (err != NULL) {
483                 struct hdp_channel *chan = dc_data->hdp_chann;
484                 GError *gerr = NULL;
485
486                 error("%s", err->message);
487                 reply = g_dbus_create_error(dc_data->msg,
488                                         ERROR_INTERFACE ".HealthError",
489                                         "Cannot reconnect: %s", err->message);
490                 g_dbus_send_message(conn, reply);
491
492                 /* Send abort request because remote side */
493                 /* is now in PENDING state */
494                 if (!mcap_mdl_abort(chan->mdl, abort_mdl_cb, NULL, NULL,
495                                                                 &gerr)) {
496                         error("%s", gerr->message);
497                         g_error_free(gerr);
498                 }
499                 return;
500         }
501
502         fd = mcap_mdl_get_fd(dc_data->hdp_chann->mdl);
503         if (fd < 0) {
504                 reply = g_dbus_create_error(dc_data->msg,
505                                                 ERROR_INTERFACE ".HealthError",
506                                                 "Cannot get file descriptor");
507                 g_dbus_send_message(conn, reply);
508                 return;
509         }
510
511         reply = g_dbus_create_reply(dc_data->msg, DBUS_TYPE_UNIX_FD,
512                                                         &fd, DBUS_TYPE_INVALID);
513         g_dbus_send_message(conn, reply);
514
515         g_dbus_emit_signal(conn, device_get_path(dc_data->hdp_chann->dev->dev),
516                         HEALTH_DEVICE, "ChannelConnected",
517                         DBUS_TYPE_OBJECT_PATH, &dc_data->hdp_chann->path,
518                         DBUS_TYPE_INVALID);
519 }
520
521 static void hdp_get_dcpsm_cb(uint16_t dcpsm, gpointer user_data, GError *err)
522 {
523         struct hdp_tmp_dc_data *hdp_conn = user_data;
524         struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
525         GError *gerr = NULL;
526         uint8_t mode;
527
528         if (err != NULL) {
529                 hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
530                 return;
531         }
532
533         if (hdp_chann->config == HDP_RELIABLE_DC)
534                 mode = BT_IO_MODE_ERTM;
535         else
536                 mode = BT_IO_MODE_STREAMING;
537
538         if (mcap_connect_mdl(hdp_chann->mdl, mode, dcpsm, hdp_conn->cb,
539                                         hdp_tmp_dc_data_ref(hdp_conn),
540                                         hdp_tmp_dc_data_destroy, &gerr))
541                 return;
542
543         hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
544         g_error_free(gerr);
545         hdp_tmp_dc_data_unref(hdp_conn);
546 }
547
548 static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
549                                                                 gpointer data)
550 {
551         DBusConnection *conn = btd_get_dbus_connection();
552         struct hdp_tmp_dc_data *dc_data = data;
553         GError *gerr = NULL;
554         DBusMessage *reply;
555
556         if (err != NULL) {
557                 reply = g_dbus_create_error(dc_data->msg,
558                                         ERROR_INTERFACE ".HealthError",
559                                         "Cannot reconnect: %s", err->message);
560                 g_dbus_send_message(conn, reply);
561                 return;
562         }
563
564         dc_data->cb = hdp_mdl_reconn_cb;
565
566         if (hdp_get_dcpsm(dc_data->hdp_chann->dev, hdp_get_dcpsm_cb,
567                                         hdp_tmp_dc_data_ref(dc_data),
568                                         hdp_tmp_dc_data_destroy, &gerr))
569                 return;
570
571         error("%s", gerr->message);
572
573         reply = g_dbus_create_error(dc_data->msg,
574                                         ERROR_INTERFACE ".HealthError",
575                                         "Cannot reconnect: %s", gerr->message);
576         g_dbus_send_message(conn, reply);
577         hdp_tmp_dc_data_unref(dc_data);
578         g_error_free(gerr);
579
580         /* Send abort request because remote side is now in PENDING state */
581         if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) {
582                 error("%s", gerr->message);
583                 g_error_free(gerr);
584         }
585 }
586
587 static DBusMessage *channel_acquire_continue(struct hdp_tmp_dc_data *data,
588                                                                 GError *err)
589 {
590         DBusMessage *reply;
591         GError *gerr = NULL;
592         int fd;
593
594         if (err != NULL) {
595                 return g_dbus_create_error(data->msg,
596                                                 ERROR_INTERFACE ".HealthError",
597                                                 "%s", err->message);
598         }
599
600         fd = mcap_mdl_get_fd(data->hdp_chann->mdl);
601         if (fd >= 0)
602                 return g_dbus_create_reply(data->msg, DBUS_TYPE_UNIX_FD, &fd,
603                                                         DBUS_TYPE_INVALID);
604
605         hdp_tmp_dc_data_ref(data);
606         if (mcap_reconnect_mdl(data->hdp_chann->mdl, device_reconnect_mdl_cb,
607                                         data, hdp_tmp_dc_data_destroy, &gerr))
608                 return NULL;
609
610         reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
611                                         "Cannot reconnect: %s", gerr->message);
612         g_error_free(gerr);
613         hdp_tmp_dc_data_unref(data);
614
615         return reply;
616 }
617
618 static void channel_acquire_cb(gpointer data, GError *err)
619 {
620         DBusMessage *reply;
621
622         reply = channel_acquire_continue(data, err);
623
624         if (reply != NULL)
625                 g_dbus_send_message(btd_get_dbus_connection(), reply);
626 }
627
628 static DBusMessage *channel_acquire(DBusConnection *conn,
629                                         DBusMessage *msg, void *user_data)
630 {
631         struct hdp_channel *chan = user_data;
632         struct hdp_tmp_dc_data *dc_data;
633         GError *gerr = NULL;
634         DBusMessage *reply;
635
636         dc_data = g_new0(struct hdp_tmp_dc_data, 1);
637         dc_data->msg = dbus_message_ref(msg);
638         dc_data->hdp_chann = hdp_channel_ref(chan);
639
640         if (chan->dev->mcl_conn) {
641                 reply = channel_acquire_continue(hdp_tmp_dc_data_ref(dc_data),
642                                                                         NULL);
643                 hdp_tmp_dc_data_unref(dc_data);
644                 return reply;
645         }
646
647         if (hdp_establish_mcl(chan->dev, channel_acquire_cb,
648                                                 hdp_tmp_dc_data_ref(dc_data),
649                                                 hdp_tmp_dc_data_destroy, &gerr))
650                 return NULL;
651
652         reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
653                                         "%s", gerr->message);
654         hdp_tmp_dc_data_unref(dc_data);
655         g_error_free(gerr);
656
657         return reply;
658 }
659
660 static void close_mdl(struct hdp_channel *hdp_chann)
661 {
662         int fd;
663
664         fd = mcap_mdl_get_fd(hdp_chann->mdl);
665         if (fd < 0)
666                 return;
667
668         close(fd);
669 }
670
671 static DBusMessage *channel_release(DBusConnection *conn,
672                                         DBusMessage *msg, void *user_data)
673 {
674         struct hdp_channel *hdp_chann = user_data;
675
676         close_mdl(hdp_chann);
677
678         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
679 }
680
681 static void free_echo_data(struct hdp_echo_data *edata)
682 {
683         if (edata == NULL)
684                 return;
685
686         if (edata->tid > 0)
687                 timeout_remove(edata->tid);
688
689         if (edata->buf != NULL)
690                 g_free(edata->buf);
691
692
693         g_free(edata);
694 }
695
696 static void health_channel_destroy(void *data)
697 {
698         struct hdp_channel *hdp_chan = data;
699         struct hdp_device *dev = hdp_chan->dev;
700
701         DBG("Destroy Health Channel %s", hdp_chan->path);
702         if (g_slist_find(dev->channels, hdp_chan) == NULL)
703                 goto end;
704
705         dev->channels = g_slist_remove(dev->channels, hdp_chan);
706
707         if (hdp_chan->mdep != HDP_MDEP_ECHO)
708                 g_dbus_emit_signal(btd_get_dbus_connection(),
709                                         device_get_path(dev->dev),
710                                         HEALTH_DEVICE, "ChannelDeleted",
711                                         DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
712                                         DBUS_TYPE_INVALID);
713
714         if (hdp_chan == dev->fr) {
715                 hdp_channel_unref(dev->fr);
716                 dev->fr = NULL;
717         }
718
719 end:
720         hdp_channel_unref(hdp_chan);
721 }
722
723 static const GDBusMethodTable health_channels_methods[] = {
724         { GDBUS_ASYNC_METHOD("Acquire",
725                         NULL, GDBUS_ARGS({ "fd", "h" }),
726                         channel_acquire) },
727         { GDBUS_METHOD("Release", NULL, NULL, channel_release) },
728         { }
729 };
730
731 static const GDBusPropertyTable health_channels_properties[] = {
732         { "Device", "o",  channel_property_get_device },
733         { "Application", "o", channel_property_get_application },
734         { "Type", "s", channel_property_get_type },
735         { }
736 };
737
738 static struct hdp_channel *create_channel(struct hdp_device *dev,
739                                                 uint8_t config,
740                                                 struct mcap_mdl *mdl,
741                                                 uint16_t mdlid,
742                                                 struct hdp_application *app,
743                                                 GError **err)
744 {
745         struct hdp_channel *hdp_chann;
746
747         if (dev == NULL) {
748                 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
749                                         "HDP device uninitialized");
750                 return NULL;
751         }
752
753         hdp_chann = g_new0(struct hdp_channel, 1);
754         hdp_chann->config = config;
755         hdp_chann->dev = health_device_ref(dev);
756         hdp_chann->mdlid = mdlid;
757
758         if (mdl != NULL)
759                 hdp_chann->mdl = mcap_mdl_ref(mdl);
760
761         if (app != NULL) {
762                 hdp_chann->mdep = app->id;
763                 hdp_chann->app = hdp_application_ref(app);
764         } else
765                 hdp_chann->edata = g_new0(struct hdp_echo_data, 1);
766
767         hdp_chann->path = g_strdup_printf("%s/chan%d",
768                                         device_get_path(hdp_chann->dev->dev),
769                                         hdp_chann->mdlid);
770
771         dev->channels = g_slist_append(dev->channels,
772                                                 hdp_channel_ref(hdp_chann));
773
774         if (hdp_chann->mdep == HDP_MDEP_ECHO)
775                 return hdp_channel_ref(hdp_chann);
776
777         if (!g_dbus_register_interface(btd_get_dbus_connection(),
778                                         hdp_chann->path, HEALTH_CHANNEL,
779                                         health_channels_methods, NULL,
780                                         health_channels_properties, hdp_chann,
781                                         health_channel_destroy)) {
782                 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
783                                         "Can't register the channel interface");
784                 health_channel_destroy(hdp_chann);
785                 return NULL;
786         }
787
788         return hdp_channel_ref(hdp_chann);
789 }
790
791 static void remove_channels(struct hdp_device *dev)
792 {
793         struct hdp_channel *chan;
794         char *path;
795
796         while (dev->channels != NULL) {
797                 chan = dev->channels->data;
798
799                 path = g_strdup(chan->path);
800                 if (!g_dbus_unregister_interface(btd_get_dbus_connection(),
801                                                         path, HEALTH_CHANNEL))
802                         health_channel_destroy(chan);
803                 g_free(path);
804         }
805 }
806
807 static void close_device_con(struct hdp_device *dev, gboolean cache)
808 {
809         if (dev->mcl == NULL)
810                 return;
811
812         mcap_close_mcl(dev->mcl, cache);
813         dev->mcl_conn = FALSE;
814
815         if (cache)
816                 return;
817
818         device_unref_mcl(dev);
819         remove_channels(dev);
820
821         if (!dev->sdp_present) {
822                 const char *path;
823
824                 path = device_get_path(dev->dev);
825                 g_dbus_unregister_interface(btd_get_dbus_connection(),
826                                                         path, HEALTH_DEVICE);
827         }
828 }
829
830 static int send_echo_data(int sock, const void *buf, uint32_t size)
831 {
832         const uint8_t *buf_b = buf;
833         uint32_t sent = 0;
834
835         while (sent < size) {
836                 int n = write(sock, buf_b + sent, size - sent);
837                 if (n < 0)
838                         return -1;
839                 sent += n;
840         }
841
842         return 0;
843 }
844
845 static gboolean serve_echo(GIOChannel *io_chan, GIOCondition cond,
846                                                                 gpointer data)
847 {
848         struct hdp_channel *chan = data;
849         uint8_t buf[MCAP_DC_MTU];
850         int fd, len;
851
852         if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
853                 hdp_channel_unref(chan);
854                 return FALSE;
855         }
856
857         if (chan->edata->echo_done)
858                 goto fail;
859
860         chan->edata->echo_done = TRUE;
861
862         fd = g_io_channel_unix_get_fd(io_chan);
863
864         len = read(fd, buf, sizeof(buf));
865         if (len < 0)
866                 goto fail;
867
868         if (send_echo_data(fd, buf, len)  >= 0)
869                 return TRUE;
870
871 fail:
872         close_device_con(chan->dev, FALSE);
873         hdp_channel_unref(chan);
874         return FALSE;
875 }
876
877 static gboolean check_channel_conf(struct hdp_channel *chan)
878 {
879         GError *err = NULL;
880         GIOChannel *io;
881         uint8_t mode;
882         uint16_t imtu, omtu;
883         int fd;
884
885         fd = mcap_mdl_get_fd(chan->mdl);
886         if (fd < 0)
887                 return FALSE;
888         io = g_io_channel_unix_new(fd);
889
890         if (!bt_io_get(io, &err,
891                         BT_IO_OPT_MODE, &mode,
892                         BT_IO_OPT_IMTU, &imtu,
893                         BT_IO_OPT_OMTU, &omtu,
894                         BT_IO_OPT_INVALID)) {
895                 error("Error: %s", err->message);
896                 g_io_channel_unref(io);
897                 g_error_free(err);
898                 return FALSE;
899         }
900
901         g_io_channel_unref(io);
902
903         switch (chan->config) {
904         case HDP_RELIABLE_DC:
905                 if (mode != BT_IO_MODE_ERTM)
906                         return FALSE;
907                 break;
908         case HDP_STREAMING_DC:
909                 if (mode != BT_IO_MODE_STREAMING)
910                         return FALSE;
911                 break;
912         default:
913                 error("Error: Connected with unknown configuration");
914                 return FALSE;
915         }
916
917         DBG("MDL imtu %d omtu %d Channel imtu %d omtu %d", imtu, omtu,
918                                                 chan->imtu, chan->omtu);
919
920         if (chan->imtu == 0)
921                 chan->imtu = imtu;
922         if (chan->omtu == 0)
923                 chan->omtu = omtu;
924
925         if (chan->imtu != imtu || chan->omtu != omtu)
926                 return FALSE;
927
928         return TRUE;
929 }
930
931 static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
932 {
933         struct hdp_device *dev = data;
934         struct hdp_channel *chan;
935
936         DBG("");
937
938         if (dev->ndc == NULL)
939                 return;
940
941         chan = dev->ndc;
942         if (chan->mdl == NULL)
943                 chan->mdl = mcap_mdl_ref(mdl);
944
945         if (g_slist_find(dev->channels, chan) == NULL)
946                 dev->channels = g_slist_prepend(dev->channels,
947                                                         hdp_channel_ref(chan));
948
949         if (!check_channel_conf(chan)) {
950                 close_mdl(chan);
951                 goto end;
952         }
953
954         if (chan->mdep == HDP_MDEP_ECHO) {
955                 GIOChannel *io;
956                 int fd;
957
958                 fd = mcap_mdl_get_fd(chan->mdl);
959                 if (fd < 0)
960                         goto end;
961
962                 chan->edata->echo_done = FALSE;
963                 io = g_io_channel_unix_new(fd);
964                 g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
965                                 serve_echo, hdp_channel_ref(chan));
966                 g_io_channel_unref(io);
967                 goto end;
968         }
969
970         g_dbus_emit_signal(btd_get_dbus_connection(), device_get_path(dev->dev),
971                                 HEALTH_DEVICE, "ChannelConnected",
972                                 DBUS_TYPE_OBJECT_PATH, &chan->path,
973                                 DBUS_TYPE_INVALID);
974
975         if (dev->fr != NULL)
976                 goto end;
977
978         dev->fr = hdp_channel_ref(chan);
979
980         g_dbus_emit_property_changed(btd_get_dbus_connection(),
981                                 device_get_path(dev->dev), HEALTH_DEVICE,
982                                 "MainChannel");
983
984 end:
985         hdp_channel_unref(dev->ndc);
986         dev->ndc = NULL;
987 }
988
989 static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
990 {
991         /* struct hdp_device *dev = data; */
992
993         DBG("");
994
995         /* Nothing to do */
996 }
997
998 static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
999 {
1000         struct hdp_device *dev = data;
1001         struct hdp_channel *chan;
1002         char *path;
1003         GSList *l;
1004
1005         DBG("");
1006
1007         l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1008         if (l == NULL)
1009                 return;
1010
1011         chan = l->data;
1012
1013         path = g_strdup(chan->path);
1014         if (!g_dbus_unregister_interface(btd_get_dbus_connection(),
1015                                                         path, HEALTH_CHANNEL))
1016                 health_channel_destroy(chan);
1017         g_free(path);
1018 }
1019
1020 static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
1021 {
1022         struct hdp_device *dev = data;
1023
1024         DBG("");
1025
1026         if (dev->ndc == NULL)
1027                 return;
1028
1029         dev->ndc->mdl = mcap_mdl_ref(mdl);
1030
1031         if (g_slist_find(dev->channels, dev->ndc) == NULL)
1032                 dev->channels = g_slist_prepend(dev->channels,
1033                                                 hdp_channel_ref(dev->ndc));
1034
1035         if (dev->ndc->mdep != HDP_MDEP_ECHO)
1036                 g_dbus_emit_signal(btd_get_dbus_connection(),
1037                                         device_get_path(dev->dev),
1038                                         HEALTH_DEVICE, "ChannelConnected",
1039                                         DBUS_TYPE_OBJECT_PATH, &dev->ndc->path,
1040                                         DBUS_TYPE_INVALID);
1041
1042         hdp_channel_unref(dev->ndc);
1043         dev->ndc = NULL;
1044 }
1045
1046 static uint8_t hdp2l2cap_mode(uint8_t hdp_mode)
1047 {
1048         return hdp_mode == HDP_STREAMING_DC ? BT_IO_MODE_STREAMING :
1049                                                                 BT_IO_MODE_ERTM;
1050 }
1051
1052 static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
1053                                 uint16_t mdlid, uint8_t *conf, void *data)
1054 {
1055         struct hdp_device *dev = data;
1056         struct hdp_application *app;
1057         GError *err = NULL;
1058         GSList *l;
1059
1060         DBG("Data channel request");
1061
1062         if (mdepid == HDP_MDEP_ECHO) {
1063                 switch (*conf) {
1064                 case HDP_NO_PREFERENCE_DC:
1065                         *conf = HDP_RELIABLE_DC;
1066                         break;
1067                 case HDP_RELIABLE_DC:
1068                         break;
1069                 case HDP_STREAMING_DC:
1070                         return MCAP_CONFIGURATION_REJECTED;
1071                 default:
1072                         /* Special case defined in HDP spec 3.4. When an invalid
1073                         * configuration is received we shall close the MCL when
1074                         * we are still processing the callback. */
1075                         close_device_con(dev, FALSE);
1076                         return MCAP_CONFIGURATION_REJECTED; /* not processed */
1077                 }
1078
1079                 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1080                                                 BT_IO_MODE_ERTM, &err)) {
1081                         error("Error: %s", err->message);
1082                         g_error_free(err);
1083                         return MCAP_MDL_BUSY;
1084                 }
1085
1086                 dev->ndc = create_channel(dev, *conf, NULL, mdlid, NULL, NULL);
1087                 if (dev->ndc == NULL)
1088                         return MCAP_MDL_BUSY;
1089
1090                 return MCAP_SUCCESS;
1091         }
1092
1093         l = g_slist_find_custom(applications, &mdepid, cmp_app_id);
1094         if (l == NULL)
1095                 return MCAP_INVALID_MDEP;
1096
1097         app = l->data;
1098
1099         /* Check if is the first dc if so,
1100         * only reliable configuration is allowed */
1101         switch (*conf) {
1102         case HDP_NO_PREFERENCE_DC:
1103                 if (app->role == HDP_SINK)
1104                         return MCAP_CONFIGURATION_REJECTED;
1105                 else if (dev->fr && app->chan_type_set)
1106                         *conf = app->chan_type;
1107                 else
1108                         *conf = HDP_RELIABLE_DC;
1109                 break;
1110         case HDP_STREAMING_DC:
1111                 if (!dev->fr || app->role == HDP_SOURCE)
1112                         return MCAP_CONFIGURATION_REJECTED;
1113                 break;
1114         case HDP_RELIABLE_DC:
1115                 if (app->role == HDP_SOURCE)
1116                         return MCAP_CONFIGURATION_REJECTED;
1117                 break;
1118         default:
1119                 /* Special case defined in HDP spec 3.4. When an invalid
1120                 * configuration is received we shall close the MCL when
1121                 * we are still processing the callback. */
1122                 close_device_con(dev, FALSE);
1123                 return MCAP_CONFIGURATION_REJECTED; /* not processed */
1124         }
1125
1126         l = g_slist_find_custom(dev->channels, &mdlid, cmp_chan_mdlid);
1127         if (l != NULL) {
1128                 struct hdp_channel *chan = l->data;
1129                 char *path;
1130
1131                 path = g_strdup(chan->path);
1132                 g_dbus_unregister_interface(btd_get_dbus_connection(),
1133                                                         path, HEALTH_CHANNEL);
1134                 g_free(path);
1135         }
1136
1137         if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1138                                                 hdp2l2cap_mode(*conf), &err)) {
1139                 error("Error: %s", err->message);
1140                 g_error_free(err);
1141                 return MCAP_MDL_BUSY;
1142         }
1143
1144         dev->ndc = create_channel(dev, *conf, NULL, mdlid, app, NULL);
1145         if (dev->ndc == NULL)
1146                 return MCAP_MDL_BUSY;
1147
1148         return MCAP_SUCCESS;
1149 }
1150
1151 static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
1152 {
1153         struct hdp_device *dev = data;
1154         struct hdp_channel *chan;
1155         GError *err = NULL;
1156         GSList *l;
1157
1158         l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1159         if (l == NULL)
1160                 return MCAP_INVALID_MDL;
1161
1162         chan = l->data;
1163
1164         if (dev->fr == NULL && chan->config != HDP_RELIABLE_DC &&
1165                                                 chan->mdep != HDP_MDEP_ECHO)
1166                 return MCAP_UNSPECIFIED_ERROR;
1167
1168         if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1169                                         hdp2l2cap_mode(chan->config), &err)) {
1170                 error("Error: %s", err->message);
1171                 g_error_free(err);
1172                 return MCAP_MDL_BUSY;
1173         }
1174
1175         dev->ndc = hdp_channel_ref(chan);
1176
1177         return MCAP_SUCCESS;
1178 }
1179
1180 gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err)
1181 {
1182         gboolean ret;
1183
1184         if (device->mcl == NULL)
1185                 return FALSE;
1186
1187         ret = mcap_mcl_set_cb(device->mcl, device, err,
1188                 MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
1189                 MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
1190                 MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
1191                 MCAP_MDL_CB_ABORTED, hdp_mcap_mdl_aborted_cb,
1192                 MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
1193                 MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
1194                 MCAP_MDL_CB_INVALID);
1195         if (ret)
1196                 return TRUE;
1197
1198         error("Can't set mcl callbacks, closing mcl");
1199         close_device_con(device, TRUE);
1200
1201         return FALSE;
1202 }
1203
1204 static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
1205 {
1206         struct hdp_device *hdp_device;
1207         bdaddr_t addr;
1208         GSList *l;
1209
1210         mcap_mcl_get_addr(mcl, &addr);
1211         l = g_slist_find_custom(devices, &addr, cmp_dev_addr);
1212         if (l == NULL) {
1213                 struct hdp_adapter *hdp_adapter = data;
1214                 struct btd_device *device;
1215
1216                 device = btd_adapter_get_device(hdp_adapter->btd_adapter,
1217                                                         &addr, BDADDR_BREDR);
1218                 if (!device)
1219                         return;
1220                 hdp_device = create_health_device(device);
1221                 if (!hdp_device)
1222                         return;
1223                 devices = g_slist_append(devices, hdp_device);
1224         } else
1225                 hdp_device = l->data;
1226
1227         hdp_device->mcl = mcap_mcl_ref(mcl);
1228         hdp_device->mcl_conn = TRUE;
1229
1230         DBG("New mcl connected from  %s", device_get_path(hdp_device->dev));
1231
1232         hdp_set_mcl_cb(hdp_device, NULL);
1233 }
1234
1235 static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
1236 {
1237         struct hdp_device *hdp_device;
1238         GSList *l;
1239
1240         l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1241         if (l == NULL)
1242                 return;
1243
1244         hdp_device = l->data;
1245         hdp_device->mcl_conn = TRUE;
1246
1247         DBG("MCL reconnected %s", device_get_path(hdp_device->dev));
1248
1249         hdp_set_mcl_cb(hdp_device, NULL);
1250 }
1251
1252 static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
1253 {
1254         struct hdp_device *hdp_device;
1255         GSList *l;
1256
1257         l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1258         if (l == NULL)
1259                 return;
1260
1261         hdp_device = l->data;
1262         hdp_device->mcl_conn = FALSE;
1263
1264         DBG("Mcl disconnected %s", device_get_path(hdp_device->dev));
1265 }
1266
1267 static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
1268 {
1269         struct hdp_device *hdp_device;
1270         const char *path;
1271         GSList *l;
1272
1273         l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1274         if (l == NULL)
1275                 return;
1276
1277         hdp_device = l->data;
1278         device_unref_mcl(hdp_device);
1279
1280         if (hdp_device->sdp_present)
1281                 return;
1282
1283         /* Because remote device hasn't announced an HDP record */
1284         /* the Bluetooth daemon won't notify when the device shall */
1285         /* be removed. Then we have to remove the HealthDevice */
1286         /* interface manually */
1287         path = device_get_path(hdp_device->dev);
1288         g_dbus_unregister_interface(btd_get_dbus_connection(),
1289                                                         path, HEALTH_DEVICE);
1290         DBG("Mcl uncached %s", path);
1291 }
1292
1293 static void check_devices_mcl(void)
1294 {
1295         struct hdp_device *dev;
1296         GSList *l, *to_delete = NULL;
1297
1298         for (l = devices; l; l = l->next) {
1299                 dev = l->data;
1300                 device_unref_mcl(dev);
1301
1302                 if (!dev->sdp_present)
1303                         to_delete = g_slist_append(to_delete, dev);
1304                 else
1305                         remove_channels(dev);
1306         }
1307
1308         for (l = to_delete; l; l = l->next) {
1309                 const char *path;
1310
1311                 path = device_get_path(dev->dev);
1312                 g_dbus_unregister_interface(btd_get_dbus_connection(),
1313                                                         path, HEALTH_DEVICE);
1314         }
1315
1316         g_slist_free(to_delete);
1317 }
1318
1319 static void release_adapter_instance(struct hdp_adapter *hdp_adapter)
1320 {
1321         if (hdp_adapter->mi == NULL)
1322                 return;
1323
1324         check_devices_mcl();
1325         mcap_release_instance(hdp_adapter->mi);
1326         mcap_instance_unref(hdp_adapter->mi);
1327         hdp_adapter->mi = NULL;
1328 }
1329
1330 static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
1331 {
1332         GError *err = NULL;
1333         const bdaddr_t *src;
1334
1335         if (applications == NULL) {
1336                 release_adapter_instance(hdp_adapter);
1337                 goto update;
1338         }
1339
1340         if (hdp_adapter->mi != NULL)
1341                 goto update;
1342
1343         src = btd_adapter_get_address(hdp_adapter->btd_adapter);
1344
1345         hdp_adapter->mi = mcap_create_instance(src,
1346                                 BT_IO_SEC_MEDIUM, 0, 0,
1347                                 mcl_connected, mcl_reconnected,
1348                                 mcl_disconnected, mcl_uncached,
1349                                 NULL, /* CSP is not used by now */
1350                                 hdp_adapter, &err);
1351         if (hdp_adapter->mi == NULL) {
1352                 error("Error creating the MCAP instance: %s", err->message);
1353                 g_error_free(err);
1354                 return FALSE;
1355         }
1356
1357         hdp_adapter->ccpsm = mcap_get_ctrl_psm(hdp_adapter->mi, &err);
1358         if (err != NULL) {
1359                 error("Error getting MCAP control PSM: %s", err->message);
1360                 goto fail;
1361         }
1362
1363         hdp_adapter->dcpsm = mcap_get_data_psm(hdp_adapter->mi, &err);
1364         if (err != NULL) {
1365                 error("Error getting MCAP data PSM: %s", err->message);
1366                 goto fail;
1367         }
1368
1369 update:
1370         if (hdp_update_sdp_record(hdp_adapter, applications))
1371                 return TRUE;
1372         error("Error updating the SDP record");
1373
1374 fail:
1375         release_adapter_instance(hdp_adapter);
1376         if (err != NULL)
1377                 g_error_free(err);
1378
1379         return FALSE;
1380 }
1381
1382 static void update_adapter_cb(void *data, void *user_data)
1383 {
1384         update_adapter(data);
1385 }
1386
1387 int hdp_adapter_register(struct btd_adapter *adapter)
1388 {
1389         struct hdp_adapter *hdp_adapter;
1390
1391         hdp_adapter = g_new0(struct hdp_adapter, 1);
1392         hdp_adapter->btd_adapter = btd_adapter_ref(adapter);
1393
1394         if(!update_adapter(hdp_adapter))
1395                 goto fail;
1396
1397         adapters = g_slist_append(adapters, hdp_adapter);
1398
1399         return 0;
1400
1401 fail:
1402         btd_adapter_unref(hdp_adapter->btd_adapter);
1403         g_free(hdp_adapter);
1404         return -1;
1405 }
1406
1407 void hdp_adapter_unregister(struct btd_adapter *adapter)
1408 {
1409         struct hdp_adapter *hdp_adapter;
1410         GSList *l;
1411
1412         l = g_slist_find_custom(adapters, adapter, cmp_adapter);
1413
1414         if (l == NULL)
1415                 return;
1416
1417         hdp_adapter = l->data;
1418         adapters = g_slist_remove(adapters, hdp_adapter);
1419         if (hdp_adapter->sdp_handler > 0)
1420                 adapter_service_remove(adapter, hdp_adapter->sdp_handler);
1421         release_adapter_instance(hdp_adapter);
1422         btd_adapter_unref(hdp_adapter->btd_adapter);
1423         g_free(hdp_adapter);
1424 }
1425
1426 static void delete_echo_channel_cb(GError *err, gpointer chan)
1427 {
1428         if (err != NULL && err->code != MCAP_INVALID_MDL) {
1429                 /* TODO: Decide if more action is required here */
1430                 error("Error deleting echo channel: %s", err->message);
1431                 return;
1432         }
1433
1434         health_channel_destroy(chan);
1435 }
1436
1437 static void delete_echo_channel(struct hdp_channel *chan)
1438 {
1439         GError *err = NULL;
1440
1441         if (!chan->dev->mcl_conn) {
1442                 error("Echo channel cannot be deleted: mcl closed");
1443                 return;
1444         }
1445
1446         if (mcap_delete_mdl(chan->mdl, delete_echo_channel_cb,
1447                                 hdp_channel_ref(chan),
1448                                 (GDestroyNotify) hdp_channel_unref, &err))
1449                 return;
1450
1451         hdp_channel_unref(chan);
1452         error("Error deleting the echo channel: %s", err->message);
1453         g_error_free(err);
1454
1455         /* TODO: Decide if more action is required here */
1456 }
1457
1458 static void abort_echo_channel_cb(GError *err, gpointer data)
1459 {
1460         struct hdp_channel *chan = data;
1461
1462         if (err != NULL && err->code != MCAP_ERROR_INVALID_OPERATION) {
1463                 error("Aborting error: %s", err->message);
1464                 if (err->code == MCAP_INVALID_MDL) {
1465                         /* MDL is removed from MCAP so we can */
1466                         /* free the data channel without sending */
1467                         /* a MD_DELETE_MDL_REQ */
1468                         /* TODO review the above comment */
1469                         /* hdp_channel_unref(chan); */
1470                 }
1471                 return;
1472         }
1473
1474         delete_echo_channel(chan);
1475 }
1476
1477 static void destroy_create_dc_data(gpointer data)
1478 {
1479         struct hdp_create_dc *dc_data = data;
1480
1481         hdp_create_data_unref(dc_data);
1482 }
1483
1484 static void *generate_echo_packet(void)
1485 {
1486         uint8_t *buf;
1487
1488         buf = g_malloc(HDP_ECHO_LEN);
1489         if (!buf)
1490                 return NULL;
1491
1492         if (getrandom(buf, HDP_ECHO_LEN, 0) < 0) {
1493                 g_free(buf);
1494                 return NULL;
1495         }
1496
1497         return buf;
1498 }
1499
1500 static gboolean check_echo(GIOChannel *io_chan, GIOCondition cond,
1501                                                                 gpointer data)
1502 {
1503         struct hdp_tmp_dc_data *hdp_conn =  data;
1504         struct hdp_echo_data *edata = hdp_conn->hdp_chann->edata;
1505         struct hdp_channel *chan = hdp_conn->hdp_chann;
1506         uint8_t buf[MCAP_DC_MTU];
1507         DBusMessage *reply;
1508         gboolean value;
1509         int fd, len;
1510
1511         if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
1512                 value = FALSE;
1513                 goto end;
1514         }
1515
1516         fd = g_io_channel_unix_get_fd(io_chan);
1517
1518         len = read(fd, buf, sizeof(buf));
1519         if (len != HDP_ECHO_LEN) {
1520                 value = FALSE;
1521                 goto end;
1522         }
1523
1524         value = (memcmp(buf, edata->buf, len) == 0);
1525
1526 end:
1527         reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_BOOLEAN, &value,
1528                                                         DBUS_TYPE_INVALID);
1529         g_dbus_send_message(btd_get_dbus_connection(), reply);
1530         timeout_remove(edata->tid);
1531         edata->tid = 0;
1532         g_free(edata->buf);
1533         edata->buf = NULL;
1534
1535         if (!value)
1536                 close_device_con(chan->dev, FALSE);
1537         else
1538                 delete_echo_channel(chan);
1539         hdp_tmp_dc_data_unref(hdp_conn);
1540
1541         return FALSE;
1542 }
1543
1544 static bool echo_timeout(gpointer data)
1545 {
1546         struct hdp_channel *chan = data;
1547         GIOChannel *io;
1548         int fd;
1549
1550         error("Error: Echo request timeout");
1551         chan->edata->tid = 0;
1552
1553         fd = mcap_mdl_get_fd(chan->mdl);
1554         if (fd < 0)
1555                 return FALSE;
1556
1557         io = g_io_channel_unix_new(fd);
1558         g_io_channel_shutdown(io, TRUE, NULL);
1559
1560         return FALSE;
1561 }
1562
1563 static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
1564                                                                 gpointer data)
1565 {
1566         DBusConnection *conn = btd_get_dbus_connection();
1567         struct hdp_tmp_dc_data *hdp_conn =  data;
1568         struct hdp_echo_data *edata;
1569         GError *gerr = NULL;
1570         DBusMessage *reply;
1571         GIOChannel *io;
1572         int fd;
1573
1574         if (err != NULL) {
1575                 reply = g_dbus_create_error(hdp_conn->msg,
1576                                                 ERROR_INTERFACE ".HealthError",
1577                                                 "%s", err->message);
1578                 g_dbus_send_message(conn, reply);
1579
1580                 /* Send abort request because remote */
1581                 /* side is now in PENDING state. */
1582                 if (!mcap_mdl_abort(hdp_conn->hdp_chann->mdl,
1583                                         abort_echo_channel_cb,
1584                                         hdp_channel_ref(hdp_conn->hdp_chann),
1585                                         (GDestroyNotify) hdp_channel_unref,
1586                                         &gerr)) {
1587                         error("%s", gerr->message);
1588                         g_error_free(gerr);
1589                         hdp_channel_unref(hdp_conn->hdp_chann);
1590                 }
1591                 return;
1592         }
1593
1594         fd = mcap_mdl_get_fd(hdp_conn->hdp_chann->mdl);
1595         if (fd < 0) {
1596                 reply = g_dbus_create_error(hdp_conn->msg,
1597                                                 ERROR_INTERFACE ".HealthError",
1598                                                 "Can't write in echo channel");
1599                 g_dbus_send_message(conn, reply);
1600                 delete_echo_channel(hdp_conn->hdp_chann);
1601                 return;
1602         }
1603
1604         edata = hdp_conn->hdp_chann->edata;
1605         edata->buf = generate_echo_packet();
1606         send_echo_data(fd, edata->buf, HDP_ECHO_LEN);
1607
1608         io = g_io_channel_unix_new(fd);
1609         g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
1610                         check_echo, hdp_tmp_dc_data_ref(hdp_conn));
1611
1612         edata->tid = timeout_add_seconds(ECHO_TIMEOUT, echo_timeout,
1613                                 hdp_channel_ref(hdp_conn->hdp_chann),
1614                                 (timeout_destroy_func_t) hdp_channel_unref);
1615
1616         g_io_channel_unref(io);
1617 }
1618
1619 static void delete_mdl_cb(GError *err, gpointer data)
1620 {
1621         if (err != NULL)
1622                 error("Deleting error: %s", err->message);
1623 }
1624
1625 static void abort_and_del_mdl_cb(GError *err, gpointer data)
1626 {
1627         struct mcap_mdl *mdl = data;
1628         GError *gerr = NULL;
1629
1630         if (err != NULL) {
1631                 error("%s", err->message);
1632                 if (err->code == MCAP_INVALID_MDL) {
1633                         /* MDL is removed from MCAP so we don't */
1634                         /* need to delete it. */
1635                         return;
1636                 }
1637         }
1638
1639         if (!mcap_delete_mdl(mdl, delete_mdl_cb, NULL, NULL, &gerr)) {
1640                 error("%s", gerr->message);
1641                 g_error_free(gerr);
1642         }
1643 }
1644
1645 static void abort_mdl_connection_cb(GError *err, gpointer data)
1646 {
1647         struct hdp_tmp_dc_data *hdp_conn = data;
1648         struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1649
1650         if (err != NULL)
1651                 error("Aborting error: %s", err->message);
1652
1653         /* Connection operation has failed but we have to */
1654         /* notify the channel created at MCAP level */
1655         if (hdp_chann->mdep != HDP_MDEP_ECHO)
1656                 g_dbus_emit_signal(btd_get_dbus_connection(),
1657                                         device_get_path(hdp_chann->dev->dev),
1658                                         HEALTH_DEVICE, "ChannelConnected",
1659                                         DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1660                                         DBUS_TYPE_INVALID);
1661 }
1662
1663 static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
1664 {
1665         DBusConnection *conn = btd_get_dbus_connection();
1666         struct hdp_tmp_dc_data *hdp_conn =  data;
1667         struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1668         struct hdp_device *dev = hdp_chann->dev;
1669         DBusMessage *reply;
1670         GError *gerr = NULL;
1671
1672         if (err != NULL) {
1673                 error("%s", err->message);
1674                 reply = g_dbus_create_reply(hdp_conn->msg,
1675                                         DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1676                                         DBUS_TYPE_INVALID);
1677                 g_dbus_send_message(conn, reply);
1678
1679                 /* Send abort request because remote side */
1680                 /* is now in PENDING state */
1681                 if (!mcap_mdl_abort(hdp_chann->mdl, abort_mdl_connection_cb,
1682                                         hdp_tmp_dc_data_ref(hdp_conn),
1683                                         hdp_tmp_dc_data_destroy, &gerr)) {
1684                         hdp_tmp_dc_data_unref(hdp_conn);
1685                         error("%s", gerr->message);
1686                         g_error_free(gerr);
1687                 }
1688                 return;
1689         }
1690
1691         reply = g_dbus_create_reply(hdp_conn->msg,
1692                                         DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1693                                         DBUS_TYPE_INVALID);
1694         g_dbus_send_message(conn, reply);
1695
1696         g_dbus_emit_signal(conn, device_get_path(hdp_chann->dev->dev),
1697                                 HEALTH_DEVICE, "ChannelConnected",
1698                                 DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1699                                 DBUS_TYPE_INVALID);
1700
1701         if (!check_channel_conf(hdp_chann)) {
1702                 close_mdl(hdp_chann);
1703                 return;
1704         }
1705
1706         if (dev->fr != NULL)
1707                 return;
1708
1709         dev->fr = hdp_channel_ref(hdp_chann);
1710
1711         g_dbus_emit_property_changed(btd_get_dbus_connection(),
1712                                 device_get_path(dev->dev), HEALTH_DEVICE,
1713                                 "MainChannel");
1714 }
1715
1716 static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
1717                                                 GError *err, gpointer data)
1718 {
1719         DBusConnection *conn = btd_get_dbus_connection();
1720         struct hdp_create_dc *user_data = data;
1721         struct hdp_tmp_dc_data *hdp_conn;
1722         struct hdp_channel *hdp_chan;
1723         GError *gerr = NULL;
1724         DBusMessage *reply;
1725
1726         if (err != NULL) {
1727                 reply = g_dbus_create_error(user_data->msg,
1728                                         ERROR_INTERFACE ".HealthError",
1729                                         "%s", err->message);
1730                 g_dbus_send_message(conn, reply);
1731                 return;
1732         }
1733
1734         if (user_data->mdep != HDP_MDEP_ECHO &&
1735                                 user_data->config == HDP_NO_PREFERENCE_DC) {
1736                 if (user_data->dev->fr == NULL && conf != HDP_RELIABLE_DC) {
1737                         g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1738                                         "Data channel aborted, first data "
1739                                         "channel should be reliable");
1740                         goto fail;
1741                 } else if (conf == HDP_NO_PREFERENCE_DC ||
1742                                                 conf > HDP_STREAMING_DC) {
1743                         g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1744                                                         "Data channel aborted, "
1745                                                         "configuration error");
1746                         goto fail;
1747                 }
1748         }
1749
1750         hdp_chan = create_channel(user_data->dev, conf, mdl,
1751                                                         mcap_mdl_get_mdlid(mdl),
1752                                                         user_data->app, &gerr);
1753         if (hdp_chan == NULL)
1754                 goto fail;
1755
1756         hdp_conn = g_new0(struct hdp_tmp_dc_data, 1);
1757         hdp_conn->msg = dbus_message_ref(user_data->msg);
1758         hdp_conn->hdp_chann = hdp_chan;
1759         hdp_conn->cb = user_data->cb;
1760         hdp_chan->mdep = user_data->mdep;
1761
1762         if (hdp_get_dcpsm(hdp_chan->dev, hdp_get_dcpsm_cb,
1763                                                 hdp_tmp_dc_data_ref(hdp_conn),
1764                                                 hdp_tmp_dc_data_destroy, &gerr))
1765                 return;
1766
1767         error("%s", gerr->message);
1768         g_error_free(gerr);
1769
1770         reply = g_dbus_create_reply(hdp_conn->msg,
1771                                         DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
1772                                         DBUS_TYPE_INVALID);
1773         g_dbus_send_message(conn, reply);
1774         hdp_tmp_dc_data_unref(hdp_conn);
1775
1776         /* Send abort request because remote side is now in PENDING state */
1777         if (!mcap_mdl_abort(hdp_chan->mdl, abort_mdl_connection_cb,
1778                                         hdp_tmp_dc_data_ref(hdp_conn),
1779                                         hdp_tmp_dc_data_destroy, &gerr)) {
1780                 hdp_tmp_dc_data_unref(hdp_conn);
1781                 error("%s", gerr->message);
1782                 g_error_free(gerr);
1783         }
1784
1785         return;
1786
1787 fail:
1788         reply = g_dbus_create_error(user_data->msg,
1789                                                 ERROR_INTERFACE ".HealthError",
1790                                                 "%s", gerr->message);
1791         g_dbus_send_message(conn, reply);
1792         g_error_free(gerr);
1793
1794         /* Send abort request because remote side is now in PENDING */
1795         /* state. Then we have to delete it because we couldn't */
1796         /* register the HealthChannel interface */
1797         if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl),
1798                                 (GDestroyNotify) mcap_mdl_unref, &gerr)) {
1799                 error("%s", gerr->message);
1800                 g_error_free(gerr);
1801                 mcap_mdl_unref(mdl);
1802         }
1803 }
1804
1805 static void device_create_dc_cb(gpointer user_data, GError *err)
1806 {
1807         DBusConnection *conn = btd_get_dbus_connection();
1808         struct hdp_create_dc *data = user_data;
1809         DBusMessage *reply;
1810         GError *gerr = NULL;
1811
1812         if (err != NULL) {
1813                 reply = g_dbus_create_error(data->msg,
1814                                         ERROR_INTERFACE ".HealthError",
1815                                         "%s", err->message);
1816                 g_dbus_send_message(conn, reply);
1817                 return;
1818         }
1819
1820         if (data->dev->mcl == NULL) {
1821                 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1822                                 "Mcl was closed");
1823                 goto fail;
1824         }
1825
1826         hdp_create_data_ref(data);
1827
1828         if (mcap_create_mdl(data->dev->mcl, data->mdep, data->config,
1829                                                 device_create_mdl_cb, data,
1830                                                 destroy_create_dc_data, &gerr))
1831                 return;
1832         hdp_create_data_unref(data);
1833
1834 fail:
1835         reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
1836                                                         "%s", gerr->message);
1837         g_error_free(gerr);
1838         g_dbus_send_message(conn, reply);
1839 }
1840
1841 static DBusMessage *device_echo(DBusConnection *conn,
1842                                         DBusMessage *msg, void *user_data)
1843 {
1844         struct hdp_device *device = user_data;
1845         struct hdp_create_dc *data;
1846         DBusMessage *reply;
1847         GError *err = NULL;
1848
1849         data = g_new0(struct hdp_create_dc, 1);
1850         data->dev = health_device_ref(device);
1851         data->mdep = HDP_MDEP_ECHO;
1852         data->config = HDP_RELIABLE_DC;
1853         data->msg = dbus_message_ref(msg);
1854         data->cb = hdp_echo_connect_cb;
1855         hdp_create_data_ref(data);
1856
1857         if (device->mcl_conn && device->mcl) {
1858                 if (mcap_create_mdl(device->mcl, data->mdep, data->config,
1859                                                 device_create_mdl_cb, data,
1860                                                 destroy_create_dc_data, &err))
1861                         return NULL;
1862                 goto fail;
1863         }
1864
1865         if (hdp_establish_mcl(data->dev, device_create_dc_cb,
1866                                         data, destroy_create_dc_data, &err))
1867                 return NULL;
1868
1869 fail:
1870         reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1871                                                         "%s", err->message);
1872         g_error_free(err);
1873         hdp_create_data_unref(data);
1874         return reply;
1875 }
1876
1877 static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
1878 {
1879         DBusConnection *conn = btd_get_dbus_connection();
1880         struct hdp_create_dc *dc_data, *user_data = data;
1881         DBusMessage *reply;
1882         GError *gerr = NULL;
1883
1884         if (err != NULL) {
1885                 reply = g_dbus_create_error(user_data->msg,
1886                                                 ERROR_INTERFACE ".HealthError",
1887                                                 "%s", err->message);
1888                 g_dbus_send_message(conn, reply);
1889                 return;
1890         }
1891
1892         dc_data = hdp_create_data_ref(user_data);
1893         dc_data->mdep = mdep;
1894
1895         if (user_data->dev->mcl_conn) {
1896                 device_create_dc_cb(dc_data, NULL);
1897                 hdp_create_data_unref(dc_data);
1898                 return;
1899         }
1900
1901         if (hdp_establish_mcl(dc_data->dev, device_create_dc_cb,
1902                                         dc_data, destroy_create_dc_data, &gerr))
1903                 return;
1904
1905         reply = g_dbus_create_error(user_data->msg,
1906                                                 ERROR_INTERFACE ".HealthError",
1907                                                 "%s", gerr->message);
1908         hdp_create_data_unref(dc_data);
1909         g_error_free(gerr);
1910         g_dbus_send_message(conn, reply);
1911 }
1912
1913 static DBusMessage *device_create_channel(DBusConnection *conn,
1914                                         DBusMessage *msg, void *user_data)
1915 {
1916         struct hdp_device *device = user_data;
1917         struct hdp_application *app;
1918         struct hdp_create_dc *data;
1919         char *app_path, *conf;
1920         DBusMessage *reply;
1921         GError *err = NULL;
1922         uint8_t config;
1923         GSList *l;
1924
1925         if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &app_path,
1926                                                         DBUS_TYPE_STRING, &conf,
1927                                                         DBUS_TYPE_INVALID))
1928                 return btd_error_invalid_args(msg);
1929
1930         l = g_slist_find_custom(applications, app_path, cmp_app);
1931         if (l == NULL)
1932                 return btd_error_invalid_args(msg);
1933
1934         app = l->data;
1935
1936         if (g_ascii_strcasecmp("reliable", conf) == 0)
1937                 config = HDP_RELIABLE_DC;
1938         else if (g_ascii_strcasecmp("streaming", conf) == 0)
1939                 config = HDP_STREAMING_DC;
1940         else if (g_ascii_strcasecmp("any", conf) == 0)
1941                 config = HDP_NO_PREFERENCE_DC;
1942         else
1943                 return btd_error_invalid_args(msg);
1944
1945         if (app->role == HDP_SINK && config != HDP_NO_PREFERENCE_DC)
1946                 return btd_error_invalid_args(msg);
1947
1948         if (app->role == HDP_SOURCE && config == HDP_NO_PREFERENCE_DC)
1949                 return btd_error_invalid_args(msg);
1950
1951         if (!device->fr && config == HDP_STREAMING_DC)
1952                 return btd_error_invalid_args(msg);
1953
1954         data = g_new0(struct hdp_create_dc, 1);
1955         data->dev = health_device_ref(device);
1956         data->config = config;
1957         data->app = hdp_application_ref(app);
1958         data->msg = dbus_message_ref(msg);
1959         data->cb = hdp_mdl_conn_cb;
1960
1961         if (hdp_get_mdep(device, l->data, device_get_mdep_cb,
1962                                                 hdp_create_data_ref(data),
1963                                                 destroy_create_dc_data, &err))
1964                 return NULL;
1965
1966         reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1967                                                         "%s", err->message);
1968         g_error_free(err);
1969         hdp_create_data_unref(data);
1970         return reply;
1971 }
1972
1973 static void hdp_mdl_delete_cb(GError *err, gpointer data)
1974 {
1975         DBusConnection *conn = btd_get_dbus_connection();
1976         struct hdp_tmp_dc_data *del_data = data;
1977         DBusMessage *reply;
1978         char *path;
1979
1980         if (err != NULL && err->code != MCAP_INVALID_MDL) {
1981                 reply = g_dbus_create_error(del_data->msg,
1982                                                 ERROR_INTERFACE ".HealthError",
1983                                                 "%s", err->message);
1984                 g_dbus_send_message(conn, reply);
1985                 return;
1986         }
1987
1988         path = g_strdup(del_data->hdp_chann->path);
1989         g_dbus_unregister_interface(conn, path, HEALTH_CHANNEL);
1990         g_free(path);
1991
1992         reply = g_dbus_create_reply(del_data->msg, DBUS_TYPE_INVALID);
1993         g_dbus_send_message(conn, reply);
1994 }
1995
1996 static void hdp_continue_del_cb(gpointer user_data, GError *err)
1997 {
1998         DBusConnection *conn = btd_get_dbus_connection();
1999         struct hdp_tmp_dc_data *del_data = user_data;
2000         GError *gerr = NULL;
2001         DBusMessage *reply;
2002
2003         if (err != NULL) {
2004                 reply = g_dbus_create_error(del_data->msg,
2005                                         ERROR_INTERFACE ".HealthError",
2006                                         "%s", err->message);
2007                 g_dbus_send_message(conn, reply);
2008                 return;
2009         }
2010
2011         if (mcap_delete_mdl(del_data->hdp_chann->mdl, hdp_mdl_delete_cb,
2012                                                 hdp_tmp_dc_data_ref(del_data),
2013                                                 hdp_tmp_dc_data_destroy, &gerr))
2014                         return;
2015
2016         reply = g_dbus_create_error(del_data->msg,
2017                                                 ERROR_INTERFACE ".HealthError",
2018                                                 "%s", gerr->message);
2019         hdp_tmp_dc_data_unref(del_data);
2020         g_error_free(gerr);
2021         g_dbus_send_message(conn, reply);
2022 }
2023
2024 static DBusMessage *device_destroy_channel(DBusConnection *conn,
2025                                         DBusMessage *msg, void *user_data)
2026 {
2027         struct hdp_device *device = user_data;
2028         struct hdp_tmp_dc_data *del_data;
2029         struct hdp_channel *hdp_chan;
2030         DBusMessage *reply;
2031         GError *err = NULL;
2032         char *path;
2033         GSList *l;
2034
2035         if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
2036                                                         DBUS_TYPE_INVALID)){
2037                 return btd_error_invalid_args(msg);
2038         }
2039
2040         l = g_slist_find_custom(device->channels, path, cmp_chan_path);
2041         if (l == NULL)
2042                 return btd_error_invalid_args(msg);
2043
2044         hdp_chan = l->data;
2045         del_data = g_new0(struct hdp_tmp_dc_data, 1);
2046         del_data->msg = dbus_message_ref(msg);
2047         del_data->hdp_chann = hdp_channel_ref(hdp_chan);
2048
2049         if (device->mcl_conn) {
2050                 if (mcap_delete_mdl(hdp_chan->mdl, hdp_mdl_delete_cb,
2051                                                 hdp_tmp_dc_data_ref(del_data),
2052                                                 hdp_tmp_dc_data_destroy, &err))
2053                         return NULL;
2054                 goto fail;
2055         }
2056
2057         if (hdp_establish_mcl(device, hdp_continue_del_cb,
2058                                                 hdp_tmp_dc_data_ref(del_data),
2059                                                 hdp_tmp_dc_data_destroy, &err))
2060                 return NULL;
2061
2062 fail:
2063         reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
2064                                                         "%s", err->message);
2065         hdp_tmp_dc_data_unref(del_data);
2066         g_error_free(err);
2067         return reply;
2068 }
2069
2070 static gboolean dev_property_exists_main_channel(
2071                                 const GDBusPropertyTable *property, void *data)
2072 {
2073         struct hdp_device *device = data;
2074         return device->fr != NULL;
2075 }
2076
2077 static gboolean dev_property_get_main_channel(
2078                                         const GDBusPropertyTable *property,
2079                                         DBusMessageIter *iter, void *data)
2080 {
2081         struct hdp_device *device = data;
2082
2083         if (device->fr == NULL)
2084                 return FALSE;
2085
2086         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2087                                                         &device->fr->path);
2088
2089         return TRUE;
2090 }
2091
2092 static void health_device_destroy(void *data)
2093 {
2094         struct hdp_device *device = data;
2095
2096         DBG("Unregistered interface %s on path %s", HEALTH_DEVICE,
2097                                                 device_get_path(device->dev));
2098
2099         remove_channels(device);
2100         if (device->ndc != NULL) {
2101                 hdp_channel_unref(device->ndc);
2102                 device->ndc = NULL;
2103         }
2104
2105         devices = g_slist_remove(devices, device);
2106         health_device_unref(device);
2107 }
2108
2109 static const GDBusMethodTable health_device_methods[] = {
2110         { GDBUS_ASYNC_METHOD("Echo",
2111                         NULL, GDBUS_ARGS({ "value", "b" }), device_echo) },
2112         { GDBUS_ASYNC_METHOD("CreateChannel",
2113                         GDBUS_ARGS({ "application", "o" },
2114                                         { "configuration", "s" }),
2115                         GDBUS_ARGS({ "channel", "o" }),
2116                         device_create_channel) },
2117         { GDBUS_ASYNC_METHOD("DestroyChannel",
2118                         GDBUS_ARGS({ "channel", "o" }), NULL,
2119                         device_destroy_channel) },
2120         { }
2121 };
2122
2123 static const GDBusSignalTable health_device_signals[] = {
2124         { GDBUS_SIGNAL("ChannelConnected",
2125                         GDBUS_ARGS({ "channel", "o" })) },
2126         { GDBUS_SIGNAL("ChannelDeleted",
2127                         GDBUS_ARGS({ "channel", "o" })) },
2128         { }
2129 };
2130
2131 static const GDBusPropertyTable health_device_properties[] = {
2132         { "MainChannel", "o", dev_property_get_main_channel, NULL,
2133                                         dev_property_exists_main_channel },
2134         { }
2135 };
2136
2137 static struct hdp_device *create_health_device(struct btd_device *device)
2138 {
2139         struct btd_adapter *adapter = device_get_adapter(device);
2140         const char *path = device_get_path(device);
2141         struct hdp_device *dev;
2142         GSList *l;
2143
2144         if (device == NULL)
2145                 return NULL;
2146
2147         dev = g_new0(struct hdp_device, 1);
2148         dev->dev = btd_device_ref(device);
2149         health_device_ref(dev);
2150
2151         l = g_slist_find_custom(adapters, adapter, cmp_adapter);
2152         if (l == NULL)
2153                 goto fail;
2154
2155         dev->hdp_adapter = l->data;
2156
2157         if (!g_dbus_register_interface(btd_get_dbus_connection(),
2158                                         path, HEALTH_DEVICE,
2159                                         health_device_methods,
2160                                         health_device_signals,
2161                                         health_device_properties,
2162                                         dev, health_device_destroy)) {
2163                 error("D-Bus failed to register %s interface", HEALTH_DEVICE);
2164                 goto fail;
2165         }
2166
2167         DBG("Registered interface %s on path %s", HEALTH_DEVICE, path);
2168         return dev;
2169
2170 fail:
2171         health_device_unref(dev);
2172         return NULL;
2173 }
2174
2175 int hdp_device_register(struct btd_device *device)
2176 {
2177         struct hdp_device *hdev;
2178         GSList *l;
2179
2180         l = g_slist_find_custom(devices, device, cmp_device);
2181         if (l != NULL) {
2182                 hdev = l->data;
2183                 hdev->sdp_present = TRUE;
2184                 return 0;
2185         }
2186
2187         hdev = create_health_device(device);
2188         if (hdev == NULL)
2189                 return -1;
2190
2191         hdev->sdp_present = TRUE;
2192
2193         devices = g_slist_prepend(devices, hdev);
2194         return 0;
2195 }
2196
2197 void hdp_device_unregister(struct btd_device *device)
2198 {
2199         struct hdp_device *hdp_dev;
2200         const char *path;
2201         GSList *l;
2202
2203         l = g_slist_find_custom(devices, device, cmp_device);
2204         if (l == NULL)
2205                 return;
2206
2207         hdp_dev = l->data;
2208         path = device_get_path(hdp_dev->dev);
2209         g_dbus_unregister_interface(btd_get_dbus_connection(),
2210                                                         path, HEALTH_DEVICE);
2211 }
2212
2213 int hdp_manager_start(void)
2214 {
2215         DBG("Starting Health manager");
2216
2217         if (!g_dbus_register_interface(btd_get_dbus_connection(),
2218                                         MANAGER_PATH, HEALTH_MANAGER,
2219                                         health_manager_methods, NULL, NULL,
2220                                         NULL, manager_path_unregister)) {
2221                 error("D-Bus failed to register %s interface", HEALTH_MANAGER);
2222                 return -1;
2223         }
2224
2225         return 0;
2226 }
2227
2228 void hdp_manager_stop(void)
2229 {
2230         g_dbus_unregister_interface(btd_get_dbus_connection(),
2231                                                 MANAGER_PATH, HEALTH_MANAGER);
2232
2233         DBG("Stopped Health manager");
2234 }
2235
2236 struct hdp_device *health_device_ref(struct hdp_device *hdp_dev)
2237 {
2238         hdp_dev->ref++;
2239
2240         DBG("(%p): ref=%d", hdp_dev, hdp_dev->ref);
2241
2242         return hdp_dev;
2243 }
2244
2245 void health_device_unref(struct hdp_device *hdp_dev)
2246 {
2247         hdp_dev->ref--;
2248
2249         DBG("(%p): ref=%d", hdp_dev, hdp_dev->ref);
2250
2251         if (hdp_dev->ref > 0)
2252                 return;
2253
2254         free_health_device(hdp_dev);
2255 }