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