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