Tizen 2.0 Release
[profile/ivi/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 #ifdef __TIZEN_PATCH__
621         reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
622                                         "Cannot reconnect: %s", gerr->message);
623         g_error_free(gerr);
624         hdp_tmp_dc_data_unref(data);
625 #else
626         hdp_tmp_dc_data_unref(data);
627         reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
628                                         "Cannot reconnect: %s", gerr->message);
629         g_error_free(gerr);
630 #endif
631
632         return reply;
633 }
634
635 static void channel_acquire_cb(gpointer data, GError *err)
636 {
637         struct hdp_tmp_dc_data *dc_data = data;
638         DBusMessage *reply;
639
640         reply = channel_acquire_continue(data, err);
641
642         if (reply != NULL)
643                 g_dbus_send_message(dc_data->conn, reply);
644 }
645
646 static DBusMessage *channel_acquire(DBusConnection *conn,
647                                         DBusMessage *msg, void *user_data)
648 {
649         struct hdp_channel *chan = user_data;
650         struct hdp_tmp_dc_data *dc_data;
651         GError *gerr = NULL;
652         DBusMessage *reply;
653
654         dc_data = g_new0(struct hdp_tmp_dc_data, 1);
655         dc_data->conn = dbus_connection_ref(conn);
656         dc_data->msg = dbus_message_ref(msg);
657         dc_data->hdp_chann = hdp_channel_ref(chan);
658
659         if (chan->dev->mcl_conn) {
660                 reply = channel_acquire_continue(hdp_tmp_dc_data_ref(dc_data),
661                                                                         NULL);
662                 hdp_tmp_dc_data_unref(dc_data);
663                 return reply;
664         }
665
666         if (hdp_establish_mcl(chan->dev, channel_acquire_cb,
667                                                 hdp_tmp_dc_data_ref(dc_data),
668                                                 hdp_tmp_dc_data_destroy, &gerr))
669                 return NULL;
670
671         reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
672                                         "%s", gerr->message);
673         hdp_tmp_dc_data_unref(dc_data);
674         g_error_free(gerr);
675
676         return reply;
677 }
678
679 static void close_mdl(struct hdp_channel *hdp_chann)
680 {
681         int fd;
682
683         fd = mcap_mdl_get_fd(hdp_chann->mdl);
684         if (fd < 0)
685                 return;
686
687         close(fd);
688 }
689
690 static DBusMessage *channel_release(DBusConnection *conn,
691                                         DBusMessage *msg, void *user_data)
692 {
693         struct hdp_channel *hdp_chann = user_data;
694
695         close_mdl(hdp_chann);
696
697         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
698 }
699
700 static void free_echo_data(struct hdp_echo_data *edata)
701 {
702         if (edata == NULL)
703                 return;
704
705         if (edata->tid > 0)
706                 g_source_remove(edata->tid);
707
708         if (edata->buf != NULL)
709                 g_free(edata->buf);
710
711
712         g_free(edata);
713 }
714
715 static void health_channel_destroy(void *data)
716 {
717         struct hdp_channel *hdp_chan = data;
718         struct hdp_device *dev = hdp_chan->dev;
719
720         DBG("Destroy Health Channel %s", hdp_chan->path);
721         if (g_slist_find(dev->channels, hdp_chan) == NULL)
722                 goto end;
723
724         dev->channels = g_slist_remove(dev->channels, hdp_chan);
725
726         if (hdp_chan->mdep != HDP_MDEP_ECHO)
727                 g_dbus_emit_signal(dev->conn, device_get_path(dev->dev),
728                                         HEALTH_DEVICE, "ChannelDeleted",
729                                         DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
730                                         DBUS_TYPE_INVALID);
731
732         if (hdp_chan == dev->fr) {
733                 hdp_channel_unref(dev->fr);
734                 dev->fr = NULL;
735         }
736
737 end:
738         hdp_channel_unref(hdp_chan);
739 }
740
741 static const GDBusMethodTable health_channels_methods[] = {
742         { GDBUS_METHOD("GetProperties",
743                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
744                         channel_get_properties) },
745         { GDBUS_ASYNC_METHOD("Acquire",
746                         NULL, GDBUS_ARGS({ "fd", "h" }),
747                         channel_acquire) },
748         { GDBUS_METHOD("Release", NULL, NULL, channel_release) },
749         { }
750 };
751
752 static struct hdp_channel *create_channel(struct hdp_device *dev,
753                                                 uint8_t config,
754                                                 struct mcap_mdl *mdl,
755                                                 uint16_t mdlid,
756                                                 struct hdp_application *app,
757                                                 GError **err)
758 {
759         struct hdp_channel *hdp_chann;
760
761         if (dev == NULL)
762                 return NULL;
763
764         hdp_chann = g_new0(struct hdp_channel, 1);
765         hdp_chann->config = config;
766         hdp_chann->dev = health_device_ref(dev);
767         hdp_chann->mdlid = mdlid;
768
769         if (mdl != NULL)
770                 hdp_chann->mdl = mcap_mdl_ref(mdl);
771
772         if (app != NULL) {
773                 hdp_chann->mdep = app->id;
774                 hdp_chann->app = hdp_application_ref(app);
775         } else
776                 hdp_chann->edata = g_new0(struct hdp_echo_data, 1);
777
778         hdp_chann->path = g_strdup_printf("%s/chan%d",
779                                         device_get_path(hdp_chann->dev->dev),
780                                         hdp_chann->mdlid);
781
782         dev->channels = g_slist_append(dev->channels,
783                                                 hdp_channel_ref(hdp_chann));
784
785         if (hdp_chann->mdep == HDP_MDEP_ECHO)
786                 return hdp_channel_ref(hdp_chann);
787
788         if (!g_dbus_register_interface(dev->conn, hdp_chann->path,
789                                         HEALTH_CHANNEL,
790                                         health_channels_methods, NULL, NULL,
791                                         hdp_chann, health_channel_destroy)) {
792                 g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
793                                         "Can't register the channel interface");
794                 health_channel_destroy(hdp_chann);
795                 return NULL;
796         }
797
798         return hdp_channel_ref(hdp_chann);
799 }
800
801 static void remove_channels(struct hdp_device *dev)
802 {
803         struct hdp_channel *chan;
804         char *path;
805
806         while (dev->channels != NULL) {
807                 chan = dev->channels->data;
808
809                 path = g_strdup(chan->path);
810                 if (!g_dbus_unregister_interface(dev->conn, path,
811                                                                 HEALTH_CHANNEL))
812                         health_channel_destroy(chan);
813                 g_free(path);
814         }
815 }
816
817 static void close_device_con(struct hdp_device *dev, gboolean cache)
818 {
819         if (dev->mcl == NULL)
820                 return;
821
822         mcap_close_mcl(dev->mcl, cache);
823         dev->mcl_conn = FALSE;
824
825         if (cache)
826                 return;
827
828         device_unref_mcl(dev);
829         remove_channels(dev);
830
831         if (!dev->sdp_present) {
832                 const char *path;
833
834                 path = device_get_path(dev->dev);
835                 g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE);
836         }
837 }
838
839 static int send_echo_data(int sock, const void *buf, uint32_t size)
840 {
841         const uint8_t *buf_b = buf;
842         uint32_t sent = 0;
843
844         while (sent < size) {
845                 int n = write(sock, buf_b + sent, size - sent);
846                 if (n < 0)
847                         return -1;
848                 sent += n;
849         }
850
851         return 0;
852 }
853
854 static gboolean serve_echo(GIOChannel *io_chan, GIOCondition cond,
855                                                                 gpointer data)
856 {
857         struct hdp_channel *chan = data;
858         uint8_t buf[MCAP_DC_MTU];
859         int fd, len;
860
861         if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
862                 hdp_channel_unref(chan);
863                 return FALSE;
864         }
865
866         if (chan->edata->echo_done)
867                 goto fail;
868
869         chan->edata->echo_done = TRUE;
870
871         fd = g_io_channel_unix_get_fd(io_chan);
872         len = read(fd, buf, sizeof(buf));
873
874         if (send_echo_data(fd, buf, len)  >= 0)
875                 return TRUE;
876
877 fail:
878         close_device_con(chan->dev, FALSE);
879         hdp_channel_unref(chan);
880         return FALSE;
881 }
882
883 static gboolean check_channel_conf(struct hdp_channel *chan)
884 {
885         GError *err = NULL;
886         GIOChannel *io;
887         uint8_t mode;
888         uint16_t imtu, omtu;
889         int fd;
890
891         fd = mcap_mdl_get_fd(chan->mdl);
892         if (fd < 0)
893                 return FALSE;
894         io = g_io_channel_unix_new(fd);
895
896         if (!bt_io_get(io, BT_IO_L2CAP, &err,
897                         BT_IO_OPT_MODE, &mode,
898                         BT_IO_OPT_IMTU, &imtu,
899                         BT_IO_OPT_OMTU, &omtu,
900                         BT_IO_OPT_INVALID)) {
901                 error("Error: %s", err->message);
902                 g_io_channel_unref(io);
903                 g_error_free(err);
904                 return FALSE;
905         }
906
907         g_io_channel_unref(io);
908
909         switch (chan->config) {
910         case HDP_RELIABLE_DC:
911                 if (mode != L2CAP_MODE_ERTM)
912                         return FALSE;
913                 break;
914         case HDP_STREAMING_DC:
915                 if (mode != L2CAP_MODE_STREAMING)
916                         return FALSE;
917                 break;
918         default:
919                 error("Error: Connected with unknown configuration");
920                 return FALSE;
921         }
922
923         DBG("MDL imtu %d omtu %d Channel imtu %d omtu %d", imtu, omtu,
924                                                 chan->imtu, chan->omtu);
925
926         if (chan->imtu == 0)
927                 chan->imtu = imtu;
928         if (chan->omtu == 0)
929                 chan->omtu = omtu;
930
931         if (chan->imtu != imtu || chan->omtu != omtu)
932                 return FALSE;
933
934         return TRUE;
935 }
936
937 static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
938 {
939         struct hdp_device *dev = data;
940         struct hdp_channel *chan;
941
942         DBG("hdp_mcap_mdl_connected_cb");
943         if (dev->ndc == NULL)
944                 return;
945
946         chan = dev->ndc;
947         if (chan->mdl == NULL)
948                 chan->mdl = mcap_mdl_ref(mdl);
949
950         if (g_slist_find(dev->channels, chan) == NULL)
951                 dev->channels = g_slist_prepend(dev->channels,
952                                                         hdp_channel_ref(chan));
953
954         if (!check_channel_conf(chan)) {
955                 close_mdl(chan);
956                 goto end;
957         }
958
959         if (chan->mdep == HDP_MDEP_ECHO) {
960                 GIOChannel *io;
961                 int fd;
962
963                 fd = mcap_mdl_get_fd(chan->mdl);
964                 if (fd < 0)
965                         goto end;
966
967                 chan->edata->echo_done = FALSE;
968                 io = g_io_channel_unix_new(fd);
969                 g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
970                                 serve_echo, hdp_channel_ref(chan));
971                 g_io_channel_unref(io);
972                 goto end;
973         }
974
975         g_dbus_emit_signal(dev->conn, device_get_path(dev->dev), HEALTH_DEVICE,
976                                         "ChannelConnected",
977                                         DBUS_TYPE_OBJECT_PATH, &chan->path,
978                                         DBUS_TYPE_INVALID);
979
980         if (dev->fr != NULL)
981                 goto end;
982
983         dev->fr = hdp_channel_ref(chan);
984
985         emit_property_changed(dev->conn, device_get_path(dev->dev),
986                                         HEALTH_DEVICE, "MainChannel",
987                                         DBUS_TYPE_OBJECT_PATH, &dev->fr->path);
988
989 end:
990         hdp_channel_unref(dev->ndc);
991         dev->ndc = NULL;
992 }
993
994 static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data)
995 {
996         /* struct hdp_device *dev = data; */
997
998         DBG("hdp_mcap_mdl_closed_cb");
999
1000         /* Nothing to do */
1001 }
1002
1003 static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
1004 {
1005         struct hdp_device *dev = data;
1006         struct hdp_channel *chan;
1007         char *path;
1008         GSList *l;
1009
1010         DBG("hdp_mcap_mdl_deleted_cb");
1011         l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1012         if (l == NULL)
1013                 return;
1014
1015         chan = l->data;
1016
1017         path = g_strdup(chan->path);
1018         if (!g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL))
1019                 health_channel_destroy(chan);
1020         g_free(path);
1021 }
1022
1023 static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
1024 {
1025         struct hdp_device *dev = data;
1026
1027         DBG("hdp_mcap_mdl_aborted_cb");
1028         if (dev->ndc == NULL)
1029                 return;
1030
1031         dev->ndc->mdl = mcap_mdl_ref(mdl);
1032
1033         if (g_slist_find(dev->channels, dev->ndc) == NULL)
1034                 dev->channels = g_slist_prepend(dev->channels,
1035                                                 hdp_channel_ref(dev->ndc));
1036
1037         if (dev->ndc->mdep != HDP_MDEP_ECHO)
1038                 g_dbus_emit_signal(dev->conn, device_get_path(dev->dev),
1039                                         HEALTH_DEVICE, "ChannelConnected",
1040                                         DBUS_TYPE_OBJECT_PATH, &dev->ndc->path,
1041                                         DBUS_TYPE_INVALID);
1042
1043         hdp_channel_unref(dev->ndc);
1044         dev->ndc = NULL;
1045 }
1046
1047 static uint8_t hdp2l2cap_mode(uint8_t hdp_mode)
1048 {
1049         return hdp_mode == HDP_STREAMING_DC ? L2CAP_MODE_STREAMING :
1050                                                                 L2CAP_MODE_ERTM;
1051 }
1052
1053 static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
1054                                 uint16_t mdlid, uint8_t *conf, void *data)
1055 {
1056         struct hdp_device *dev = data;
1057         struct hdp_application *app;
1058         GError *err = NULL;
1059         GSList *l;
1060
1061         DBG("Data channel request");
1062
1063         if (mdepid == HDP_MDEP_ECHO) {
1064                 switch (*conf) {
1065                 case HDP_NO_PREFERENCE_DC:
1066                         *conf = HDP_RELIABLE_DC;
1067                 case HDP_RELIABLE_DC:
1068                         break;
1069                 case HDP_STREAMING_DC:
1070                         return MCAP_CONFIGURATION_REJECTED;
1071                 default:
1072                         /* Special case defined in HDP spec 3.4. When an invalid
1073                         * configuration is received we shall close the MCL when
1074                         * we are still processing the callback. */
1075                         close_device_con(dev, FALSE);
1076                         return MCAP_CONFIGURATION_REJECTED; /* not processed */
1077                 }
1078
1079                 if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1080                                                 L2CAP_MODE_ERTM, &err)) {
1081                         error("Error: %s", err->message);
1082                         g_error_free(err);
1083                         return MCAP_MDL_BUSY;
1084                 }
1085
1086                 dev->ndc = create_channel(dev, *conf, NULL, mdlid, NULL, NULL);
1087                 if (dev->ndc == NULL)
1088                         return MCAP_MDL_BUSY;
1089
1090                 return MCAP_SUCCESS;
1091         }
1092
1093         l = g_slist_find_custom(applications, &mdepid, cmp_app_id);
1094         if (l == NULL)
1095                 return MCAP_INVALID_MDEP;
1096
1097         app = l->data;
1098
1099         /* Check if is the first dc if so,
1100         * only reliable configuration is allowed */
1101         switch (*conf) {
1102         case HDP_NO_PREFERENCE_DC:
1103                 if (app->role == HDP_SINK)
1104                         return MCAP_CONFIGURATION_REJECTED;
1105                 else if (dev->fr && app->chan_type_set)
1106                         *conf = app->chan_type;
1107                 else
1108                         *conf = HDP_RELIABLE_DC;
1109                 break;
1110         case HDP_STREAMING_DC:
1111                 if (!dev->fr || app->role == HDP_SOURCE)
1112                         return MCAP_CONFIGURATION_REJECTED;
1113         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(dev->conn, path, HEALTH_CHANNEL);
1132                 g_free(path);
1133         }
1134
1135         if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1136                                                 hdp2l2cap_mode(*conf), &err)) {
1137                 error("Error: %s", err->message);
1138                 g_error_free(err);
1139                 return MCAP_MDL_BUSY;
1140         }
1141
1142         dev->ndc = create_channel(dev, *conf, NULL, mdlid, app, NULL);
1143         if (dev->ndc == NULL)
1144                 return MCAP_MDL_BUSY;
1145
1146         return MCAP_SUCCESS;
1147 }
1148
1149 static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
1150 {
1151         struct hdp_device *dev = data;
1152         struct hdp_channel *chan;
1153         GError *err = NULL;
1154         GSList *l;
1155
1156         l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
1157         if (l == NULL)
1158                 return MCAP_INVALID_MDL;
1159
1160         chan = l->data;
1161
1162         if (dev->fr == NULL && chan->config != HDP_RELIABLE_DC &&
1163                                                 chan->mdep != HDP_MDEP_ECHO)
1164                 return MCAP_UNSPECIFIED_ERROR;
1165
1166         if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
1167                                         hdp2l2cap_mode(chan->config), &err)) {
1168                 error("Error: %s", err->message);
1169                 g_error_free(err);
1170                 return MCAP_MDL_BUSY;
1171         }
1172
1173         dev->ndc = hdp_channel_ref(chan);
1174
1175         return MCAP_SUCCESS;
1176 }
1177
1178 gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err)
1179 {
1180         gboolean ret;
1181
1182         if (device->mcl == NULL)
1183                 return FALSE;
1184
1185         ret = mcap_mcl_set_cb(device->mcl, device, err,
1186                 MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb,
1187                 MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb,
1188                 MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb,
1189                 MCAP_MDL_CB_ABORTED, hdp_mcap_mdl_aborted_cb,
1190                 MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb,
1191                 MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb,
1192                 MCAP_MDL_CB_INVALID);
1193
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                 char str[18];
1215
1216                 ba2str(&addr, str);
1217                 device = adapter_get_device(connection,
1218                                         hdp_adapter->btd_adapter, str);
1219                 if (!device)
1220                         return;
1221                 hdp_device = create_health_device(connection, device);
1222                 if (!hdp_device)
1223                         return;
1224                 devices = g_slist_append(devices, hdp_device);
1225         } else
1226                 hdp_device = l->data;
1227
1228         hdp_device->mcl = mcap_mcl_ref(mcl);
1229         hdp_device->mcl_conn = TRUE;
1230
1231         DBG("New mcl connected from  %s", device_get_path(hdp_device->dev));
1232
1233         hdp_set_mcl_cb(hdp_device, NULL);
1234 }
1235
1236 static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
1237 {
1238         struct hdp_device *hdp_device;
1239         GSList *l;
1240
1241         l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1242         if (l == NULL)
1243                 return;
1244
1245         hdp_device = l->data;
1246         hdp_device->mcl_conn = TRUE;
1247
1248         DBG("MCL reconnected %s", device_get_path(hdp_device->dev));
1249
1250         hdp_set_mcl_cb(hdp_device, NULL);
1251 }
1252
1253 static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
1254 {
1255         struct hdp_device *hdp_device;
1256         GSList *l;
1257
1258         l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1259         if (l == NULL)
1260                 return;
1261
1262         hdp_device = l->data;
1263         hdp_device->mcl_conn = FALSE;
1264
1265         DBG("Mcl disconnected %s", device_get_path(hdp_device->dev));
1266 }
1267
1268 static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
1269 {
1270         struct hdp_device *hdp_device;
1271         const char *path;
1272         GSList *l;
1273
1274         l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
1275         if (l == NULL)
1276                 return;
1277
1278         hdp_device = l->data;
1279         device_unref_mcl(hdp_device);
1280
1281         if (hdp_device->sdp_present)
1282                 return;
1283
1284         /* Because remote device hasn't announced an HDP record */
1285         /* the Bluetooth daemon won't notify when the device shall */
1286         /* be removed. Then we have to remove the HealthDevice */
1287         /* interface manually */
1288         path = device_get_path(hdp_device->dev);
1289         g_dbus_unregister_interface(hdp_device->conn, path, HEALTH_DEVICE);
1290         DBG("Mcl uncached %s", path);
1291 }
1292
1293 static void check_devices_mcl(void)
1294 {
1295         struct hdp_device *dev;
1296         GSList *l, *to_delete = NULL;
1297
1298         for (l = devices; l; l = l->next) {
1299                 dev = l->data;
1300                 device_unref_mcl(dev);
1301
1302                 if (!dev->sdp_present)
1303                         to_delete = g_slist_append(to_delete, dev);
1304                 else
1305                         remove_channels(dev);
1306         }
1307
1308         for (l = to_delete; l; l = l->next) {
1309                 const char *path;
1310
1311                 path = device_get_path(dev->dev);
1312                 g_dbus_unregister_interface(dev->conn, 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         bdaddr_t addr;
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         adapter_get_address(hdp_adapter->btd_adapter, &addr);
1343         hdp_adapter->mi = mcap_create_instance(&addr, BT_IO_SEC_MEDIUM, 0, 0,
1344                                         mcl_connected, mcl_reconnected,
1345                                         mcl_disconnected, mcl_uncached,
1346                                         NULL, /* CSP is not used by now */
1347                                         hdp_adapter, &err);
1348
1349         if (hdp_adapter->mi == NULL) {
1350                 error("Error creating the MCAP instance: %s", err->message);
1351                 g_error_free(err);
1352                 return FALSE;
1353         }
1354
1355         hdp_adapter->ccpsm = mcap_get_ctrl_psm(hdp_adapter->mi, &err);
1356         if (err != NULL) {
1357                 error("Error getting MCAP control PSM: %s", err->message);
1358                 goto fail;
1359         }
1360
1361         hdp_adapter->dcpsm = mcap_get_data_psm(hdp_adapter->mi, &err);
1362         if (err != NULL) {
1363                 error("Error getting MCAP data PSM: %s", err->message);
1364                 goto fail;
1365         }
1366
1367 update:
1368         if (hdp_update_sdp_record(hdp_adapter, applications))
1369                 return TRUE;
1370         error("Error updating the SDP record");
1371
1372 fail:
1373         release_adapter_instance(hdp_adapter);
1374         if (err != NULL)
1375                 g_error_free(err);
1376
1377         return FALSE;
1378 }
1379
1380 int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *adapter)
1381 {
1382         struct hdp_adapter *hdp_adapter;
1383
1384         hdp_adapter = g_new0(struct hdp_adapter, 1);
1385         hdp_adapter->btd_adapter = btd_adapter_ref(adapter);
1386
1387         if(!update_adapter(hdp_adapter))
1388                 goto fail;
1389
1390         adapters = g_slist_append(adapters, hdp_adapter);
1391
1392         return 0;
1393
1394 fail:
1395         btd_adapter_unref(hdp_adapter->btd_adapter);
1396         g_free(hdp_adapter);
1397         return -1;
1398 }
1399
1400 void hdp_adapter_unregister(struct btd_adapter *adapter)
1401 {
1402         struct hdp_adapter *hdp_adapter;
1403         GSList *l;
1404
1405         l = g_slist_find_custom(adapters, adapter, cmp_adapter);
1406
1407         if (l == NULL)
1408                 return;
1409
1410         hdp_adapter = l->data;
1411         adapters = g_slist_remove(adapters, hdp_adapter);
1412         if (hdp_adapter->sdp_handler > 0)
1413                 remove_record_from_server(hdp_adapter->sdp_handler);
1414         release_adapter_instance(hdp_adapter);
1415         btd_adapter_unref(hdp_adapter->btd_adapter);
1416         g_free(hdp_adapter);
1417 }
1418
1419 static void delete_echo_channel_cb(GError *err, gpointer chan)
1420 {
1421         if (err != NULL && err->code != MCAP_INVALID_MDL) {
1422                 /* TODO: Decide if more action is required here */
1423                 error("Error deleting echo channel: %s", err->message);
1424                 return;
1425         }
1426
1427         health_channel_destroy(chan);
1428 }
1429
1430 static void delete_echo_channel(struct hdp_channel *chan)
1431 {
1432         GError *err = NULL;
1433
1434         if (!chan->dev->mcl_conn) {
1435                 error("Echo channel cannot be deleted: mcl closed");
1436                 return;
1437         }
1438
1439         if (mcap_delete_mdl(chan->mdl, delete_echo_channel_cb,
1440                                 hdp_channel_ref(chan),
1441                                 (GDestroyNotify) hdp_channel_unref, &err))
1442                 return;
1443
1444         hdp_channel_unref(chan);
1445         error("Error deleting the echo channel: %s", err->message);
1446         g_error_free(err);
1447
1448         /* TODO: Decide if more action is required here */
1449 }
1450
1451 static void abort_echo_channel_cb(GError *err, gpointer data)
1452 {
1453         struct hdp_channel *chan = data;
1454
1455         if (err != NULL && err->code != MCAP_ERROR_INVALID_OPERATION) {
1456                 error("Aborting error: %s", err->message);
1457                 if (err->code == MCAP_INVALID_MDL) {
1458                         /* MDL is removed from MCAP so we can */
1459                         /* free the data channel without sending */
1460                         /* a MD_DELETE_MDL_REQ */
1461                         /* TODO review the above comment */
1462                         /* hdp_channel_unref(chan); */
1463                 }
1464                 return;
1465         }
1466
1467         delete_echo_channel(chan);
1468 }
1469
1470 static void destroy_create_dc_data(gpointer data)
1471 {
1472         struct hdp_create_dc *dc_data = data;
1473
1474         hdp_create_data_unref(dc_data);
1475 }
1476
1477 static void *generate_echo_packet(void)
1478 {
1479         uint8_t *buf;
1480         int i;
1481
1482         buf = g_malloc(HDP_ECHO_LEN);
1483         srand(time(NULL));
1484
1485         for(i = 0; i < HDP_ECHO_LEN; i++)
1486                 buf[i] = rand() % UINT8_MAX;
1487
1488         return buf;
1489 }
1490
1491 static gboolean check_echo(GIOChannel *io_chan, GIOCondition cond,
1492                                                                 gpointer data)
1493 {
1494         struct hdp_tmp_dc_data *hdp_conn =  data;
1495         struct hdp_echo_data *edata = hdp_conn->hdp_chann->edata;
1496         struct hdp_channel *chan = hdp_conn->hdp_chann;
1497         uint8_t buf[MCAP_DC_MTU];
1498         DBusMessage *reply;
1499         gboolean value;
1500         int fd, len;
1501
1502         if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
1503                 value = FALSE;
1504                 goto end;
1505         }
1506
1507         fd = g_io_channel_unix_get_fd(io_chan);
1508         len = read(fd, buf, sizeof(buf));
1509
1510         if (len != HDP_ECHO_LEN) {
1511                 value = FALSE;
1512                 goto end;
1513         }
1514
1515         value = (memcmp(buf, edata->buf, len) == 0);
1516
1517 end:
1518         reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_BOOLEAN, &value,
1519                                                         DBUS_TYPE_INVALID);
1520         g_dbus_send_message(hdp_conn->conn, reply);
1521         g_source_remove(edata->tid);
1522         edata->tid = 0;
1523         g_free(edata->buf);
1524         edata->buf = NULL;
1525
1526         if (!value)
1527                 close_device_con(chan->dev, FALSE);
1528         else
1529                 delete_echo_channel(chan);
1530         hdp_tmp_dc_data_unref(hdp_conn);
1531
1532         return FALSE;
1533 }
1534
1535 static gboolean echo_timeout(gpointer data)
1536 {
1537         struct hdp_channel *chan = data;
1538         GIOChannel *io;
1539         int fd;
1540
1541         error("Error: Echo request timeout");
1542         chan->edata->tid = 0;
1543
1544         fd = mcap_mdl_get_fd(chan->mdl);
1545         if (fd < 0)
1546                 return FALSE;
1547
1548         io = g_io_channel_unix_new(fd);
1549         g_io_channel_shutdown(io, TRUE, NULL);
1550
1551         return FALSE;
1552 }
1553
1554 static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
1555                                                                 gpointer data)
1556 {
1557         struct hdp_tmp_dc_data *hdp_conn =  data;
1558         struct hdp_echo_data *edata;
1559         GError *gerr = NULL;
1560         DBusMessage *reply;
1561         GIOChannel *io;
1562         int fd;
1563
1564         if (err != NULL) {
1565                 reply = g_dbus_create_error(hdp_conn->msg,
1566                                                 ERROR_INTERFACE ".HealthError",
1567                                                 "%s", err->message);
1568                 g_dbus_send_message(hdp_conn->conn, reply);
1569
1570                 /* Send abort request because remote */
1571                 /* side is now in PENDING state. */
1572                 if (!mcap_mdl_abort(hdp_conn->hdp_chann->mdl,
1573                                         abort_echo_channel_cb,
1574                                         hdp_channel_ref(hdp_conn->hdp_chann),
1575                                         (GDestroyNotify) hdp_channel_unref,
1576                                         &gerr)) {
1577                         error("%s", gerr->message);
1578                         g_error_free(gerr);
1579                         hdp_channel_unref(hdp_conn->hdp_chann);
1580                 }
1581                 return;
1582         }
1583
1584         fd = mcap_mdl_get_fd(hdp_conn->hdp_chann->mdl);
1585         if (fd < 0) {
1586                 reply = g_dbus_create_error(hdp_conn->msg,
1587                                                 ERROR_INTERFACE ".HealthError",
1588                                                 "Can't write in echo channel");
1589                 g_dbus_send_message(hdp_conn->conn, reply);
1590                 delete_echo_channel(hdp_conn->hdp_chann);
1591                 return;
1592         }
1593
1594         edata = hdp_conn->hdp_chann->edata;
1595         edata->buf = generate_echo_packet();
1596         send_echo_data(fd, edata->buf, HDP_ECHO_LEN);
1597
1598         io = g_io_channel_unix_new(fd);
1599         g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
1600                         check_echo, hdp_tmp_dc_data_ref(hdp_conn));
1601
1602         edata->tid = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
1603                                         ECHO_TIMEOUT, echo_timeout,
1604                                         hdp_channel_ref(hdp_conn->hdp_chann),
1605                                         (GDestroyNotify) hdp_channel_unref);
1606
1607         g_io_channel_unref(io);
1608 }
1609
1610 static void delete_mdl_cb(GError *err, gpointer data)
1611 {
1612         if (err != NULL)
1613                 error("Deleting error: %s", err->message);
1614 }
1615
1616 static void abort_and_del_mdl_cb(GError *err, gpointer data)
1617 {
1618         struct mcap_mdl *mdl = data;
1619         GError *gerr = NULL;
1620
1621         if (err != NULL) {
1622                 error("%s", err->message);
1623                 if (err->code == MCAP_INVALID_MDL) {
1624                         /* MDL is removed from MCAP so we don't */
1625                         /* need to delete it. */
1626                         return;
1627                 }
1628         }
1629
1630         if (!mcap_delete_mdl(mdl, delete_mdl_cb, NULL, NULL, &gerr)) {
1631                 error("%s", gerr->message);
1632                 g_error_free(gerr);
1633         }
1634 }
1635
1636 static void abort_mdl_connection_cb(GError *err, gpointer data)
1637 {
1638         struct hdp_tmp_dc_data *hdp_conn = data;
1639         struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1640
1641         if (err != NULL)
1642                 error("Aborting error: %s", err->message);
1643
1644         /* Connection operation has failed but we have to */
1645         /* notify the channel created at MCAP level */
1646         if (hdp_chann->mdep != HDP_MDEP_ECHO)
1647                 g_dbus_emit_signal(hdp_conn->conn,
1648                                         device_get_path(hdp_chann->dev->dev),
1649                                         HEALTH_DEVICE,
1650                                         "ChannelConnected",
1651                                         DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1652                                         DBUS_TYPE_INVALID);
1653 }
1654
1655 static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
1656 {
1657         struct hdp_tmp_dc_data *hdp_conn =  data;
1658         struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
1659         struct hdp_device *dev = hdp_chann->dev;
1660         DBusMessage *reply;
1661         GError *gerr = NULL;
1662
1663         if (err != NULL) {
1664                 error("%s", err->message);
1665                 reply = g_dbus_create_reply(hdp_conn->msg,
1666                                         DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1667                                         DBUS_TYPE_INVALID);
1668                 g_dbus_send_message(hdp_conn->conn, reply);
1669
1670                 /* Send abort request because remote side */
1671                 /* is now in PENDING state */
1672                 if (!mcap_mdl_abort(hdp_chann->mdl, abort_mdl_connection_cb,
1673                                         hdp_tmp_dc_data_ref(hdp_conn),
1674                                         hdp_tmp_dc_data_destroy, &gerr)) {
1675                         hdp_tmp_dc_data_unref(hdp_conn);
1676                         error("%s", gerr->message);
1677                         g_error_free(gerr);
1678                 }
1679                 return;
1680         }
1681
1682         reply = g_dbus_create_reply(hdp_conn->msg,
1683                                         DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1684                                         DBUS_TYPE_INVALID);
1685         g_dbus_send_message(hdp_conn->conn, reply);
1686
1687         g_dbus_emit_signal(hdp_conn->conn,
1688                                         device_get_path(hdp_chann->dev->dev),
1689                                         HEALTH_DEVICE,
1690                                         "ChannelConnected",
1691                                         DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
1692                                         DBUS_TYPE_INVALID);
1693
1694         if (!check_channel_conf(hdp_chann)) {
1695                 close_mdl(hdp_chann);
1696                 return;
1697         }
1698
1699         if (dev->fr != NULL)
1700                 return;
1701
1702         dev->fr = hdp_channel_ref(hdp_chann);
1703
1704         emit_property_changed(dev->conn, device_get_path(dev->dev),
1705                                         HEALTH_DEVICE, "MainChannel",
1706                                         DBUS_TYPE_OBJECT_PATH, &dev->fr->path);
1707 }
1708
1709 static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
1710                                                 GError *err, gpointer data)
1711 {
1712         struct hdp_create_dc *user_data = data;
1713         struct hdp_tmp_dc_data *hdp_conn;
1714         struct hdp_channel *hdp_chan;
1715         GError *gerr = NULL;
1716         DBusMessage *reply;
1717
1718         if (err != NULL) {
1719                 reply = g_dbus_create_error(user_data->msg,
1720                                         ERROR_INTERFACE ".HealthError",
1721                                         "%s", err->message);
1722                 g_dbus_send_message(user_data->conn, reply);
1723                 return;
1724         }
1725
1726         if (user_data->mdep != HDP_MDEP_ECHO &&
1727                                 user_data->config == HDP_NO_PREFERENCE_DC) {
1728                 if (user_data->dev->fr == NULL && conf != HDP_RELIABLE_DC) {
1729                         g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1730                                         "Data channel aborted, first data "
1731                                         "channel should be reliable");
1732                         goto fail;
1733                 } else if (conf == HDP_NO_PREFERENCE_DC ||
1734                                                 conf > HDP_STREAMING_DC) {
1735                         g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1736                                                         "Data channel aborted, "
1737                                                         "configuration error");
1738                         goto fail;
1739                 }
1740         }
1741
1742         hdp_chan = create_channel(user_data->dev, conf, mdl,
1743                                                         mcap_mdl_get_mdlid(mdl),
1744                                                         user_data->app, &gerr);
1745         if (hdp_chan == NULL)
1746                 goto fail;
1747
1748         hdp_conn = g_new0(struct hdp_tmp_dc_data, 1);
1749         hdp_conn->msg = dbus_message_ref(user_data->msg);
1750         hdp_conn->conn = dbus_connection_ref(user_data->conn);
1751         hdp_conn->hdp_chann = hdp_chan;
1752         hdp_conn->cb = user_data->cb;
1753         hdp_chan->mdep = user_data->mdep;
1754
1755         if (hdp_get_dcpsm(hdp_chan->dev, hdp_get_dcpsm_cb,
1756                                                 hdp_tmp_dc_data_ref(hdp_conn),
1757                                                 hdp_tmp_dc_data_destroy, &gerr))
1758                 return;
1759
1760         error("%s", gerr->message);
1761         g_error_free(gerr);
1762
1763         reply = g_dbus_create_reply(hdp_conn->msg,
1764                                         DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
1765                                         DBUS_TYPE_INVALID);
1766         g_dbus_send_message(hdp_conn->conn, reply);
1767         hdp_tmp_dc_data_unref(hdp_conn);
1768
1769         /* Send abort request because remote side is now in PENDING state */
1770         if (!mcap_mdl_abort(hdp_chan->mdl, abort_mdl_connection_cb,
1771                                         hdp_tmp_dc_data_ref(hdp_conn),
1772                                         hdp_tmp_dc_data_destroy, &gerr)) {
1773                 hdp_tmp_dc_data_unref(hdp_conn);
1774                 error("%s", gerr->message);
1775                 g_error_free(gerr);
1776         }
1777
1778         return;
1779
1780 fail:
1781         reply = g_dbus_create_error(user_data->msg,
1782                                                 ERROR_INTERFACE ".HealthError",
1783                                                 "%s", gerr->message);
1784         g_dbus_send_message(user_data->conn, reply);
1785         g_error_free(gerr);
1786
1787         /* Send abort request because remote side is now in PENDING */
1788         /* state. Then we have to delete it because we couldn't */
1789         /* register the HealthChannel interface */
1790         if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl),
1791                                 (GDestroyNotify) mcap_mdl_unref, &gerr)) {
1792                 error("%s", gerr->message);
1793                 g_error_free(gerr);
1794                 mcap_mdl_unref(mdl);
1795         }
1796 }
1797
1798 static void device_create_dc_cb(gpointer user_data, GError *err)
1799 {
1800         struct hdp_create_dc *data = user_data;
1801         DBusMessage *reply;
1802         GError *gerr = NULL;
1803
1804         if (err != NULL) {
1805                 reply = g_dbus_create_error(data->msg,
1806                                         ERROR_INTERFACE ".HealthError",
1807                                         "%s", err->message);
1808                 g_dbus_send_message(data->conn, reply);
1809                 return;
1810         }
1811
1812         if (data->dev->mcl == NULL) {
1813                 g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
1814                                 "Mcl was closed");
1815                 goto fail;
1816         }
1817
1818         hdp_create_data_ref(data);
1819
1820         if (mcap_create_mdl(data->dev->mcl, data->mdep, data->config,
1821                                                 device_create_mdl_cb, data,
1822                                                 destroy_create_dc_data, &gerr))
1823                 return;
1824         hdp_create_data_unref(data);
1825
1826 fail:
1827         reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
1828                                                         "%s", gerr->message);
1829         g_error_free(gerr);
1830         g_dbus_send_message(data->conn, reply);
1831 }
1832
1833 static DBusMessage *device_echo(DBusConnection *conn,
1834                                         DBusMessage *msg, void *user_data)
1835 {
1836         struct hdp_device *device = user_data;
1837         struct hdp_create_dc *data;
1838         DBusMessage *reply;
1839         GError *err = NULL;
1840
1841         data = g_new0(struct hdp_create_dc, 1);
1842         data->dev = health_device_ref(device);
1843         data->mdep = HDP_MDEP_ECHO;
1844         data->config = HDP_RELIABLE_DC;
1845         data->msg = dbus_message_ref(msg);
1846         data->conn = dbus_connection_ref(conn);
1847         data->cb = hdp_echo_connect_cb;
1848         hdp_create_data_ref(data);
1849
1850         if (device->mcl_conn && device->mcl != NULL) {
1851                 if (mcap_create_mdl(device->mcl, data->mdep, data->config,
1852                                                 device_create_mdl_cb, data,
1853                                                 destroy_create_dc_data, &err))
1854                         return NULL;
1855                 goto fail;
1856         }
1857
1858         if (hdp_establish_mcl(data->dev, device_create_dc_cb,
1859                                         data, destroy_create_dc_data, &err))
1860                 return NULL;
1861
1862 fail:
1863         reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1864                                                         "%s", err->message);
1865         g_error_free(err);
1866         hdp_create_data_unref(data);
1867         return reply;
1868 }
1869
1870 static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
1871 {
1872         struct hdp_create_dc *dc_data, *user_data = data;
1873         DBusMessage *reply;
1874         GError *gerr = NULL;
1875
1876         if (err != NULL) {
1877                 reply = g_dbus_create_error(user_data->msg,
1878                                                 ERROR_INTERFACE ".HealthError",
1879                                                 "%s", err->message);
1880                 g_dbus_send_message(user_data->conn, reply);
1881                 return;
1882         }
1883
1884         dc_data = hdp_create_data_ref(user_data);
1885         dc_data->mdep = mdep;
1886
1887         if (user_data->dev->mcl_conn) {
1888                 device_create_dc_cb(dc_data, NULL);
1889                 hdp_create_data_unref(dc_data);
1890                 return;
1891         }
1892
1893         if (hdp_establish_mcl(dc_data->dev, device_create_dc_cb,
1894                                         dc_data, destroy_create_dc_data, &gerr))
1895                 return;
1896
1897         reply = g_dbus_create_error(user_data->msg,
1898                                                 ERROR_INTERFACE ".HealthError",
1899                                                 "%s", gerr->message);
1900         hdp_create_data_unref(dc_data);
1901         g_error_free(gerr);
1902         g_dbus_send_message(user_data->conn, reply);
1903 }
1904
1905 static DBusMessage *device_create_channel(DBusConnection *conn,
1906                                         DBusMessage *msg, void *user_data)
1907 {
1908         struct hdp_device *device = user_data;
1909         struct hdp_application *app;
1910         struct hdp_create_dc *data;
1911         char *app_path, *conf;
1912         DBusMessage *reply;
1913         GError *err = NULL;
1914         uint8_t config;
1915         GSList *l;
1916
1917         if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &app_path,
1918                                                         DBUS_TYPE_STRING, &conf,
1919                                                         DBUS_TYPE_INVALID))
1920                 return btd_error_invalid_args(msg);
1921
1922         l = g_slist_find_custom(applications, app_path, cmp_app);
1923         if (l == NULL)
1924                 return btd_error_invalid_args(msg);
1925
1926         app = l->data;
1927
1928         if (g_ascii_strcasecmp("Reliable", conf) == 0)
1929                 config = HDP_RELIABLE_DC;
1930         else if (g_ascii_strcasecmp("Streaming", conf) == 0)
1931                 config = HDP_STREAMING_DC;
1932         else if (g_ascii_strcasecmp("Any", conf) == 0)
1933                 config = HDP_NO_PREFERENCE_DC;
1934         else
1935                 return btd_error_invalid_args(msg);
1936
1937         if (app->role == HDP_SINK && config != HDP_NO_PREFERENCE_DC)
1938                 return btd_error_invalid_args(msg);
1939
1940         if (app->role == HDP_SOURCE && config == HDP_NO_PREFERENCE_DC)
1941                 return btd_error_invalid_args(msg);
1942
1943         if (!device->fr && config == HDP_STREAMING_DC)
1944                 return btd_error_invalid_args(msg);
1945
1946         data = g_new0(struct hdp_create_dc, 1);
1947         data->dev = health_device_ref(device);
1948         data->config = config;
1949         data->app = hdp_application_ref(app);
1950         data->msg = dbus_message_ref(msg);
1951         data->conn = dbus_connection_ref(conn);
1952         data->cb = hdp_mdl_conn_cb;
1953
1954         if (hdp_get_mdep(device, l->data, device_get_mdep_cb,
1955                                                 hdp_create_data_ref(data),
1956                                                 destroy_create_dc_data, &err))
1957                 return NULL;
1958
1959         reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
1960                                                         "%s", err->message);
1961         g_error_free(err);
1962         hdp_create_data_unref(data);
1963         return reply;
1964 }
1965
1966 static void hdp_mdl_delete_cb(GError *err, gpointer data)
1967 {
1968         struct hdp_tmp_dc_data *del_data = data;
1969         DBusMessage *reply;
1970         char *path;
1971
1972         if (err != NULL && err->code != MCAP_INVALID_MDL) {
1973                 reply = g_dbus_create_error(del_data->msg,
1974                                                 ERROR_INTERFACE ".HealthError",
1975                                                 "%s", err->message);
1976                 g_dbus_send_message(del_data->conn, reply);
1977                 return;
1978         }
1979
1980         path = g_strdup(del_data->hdp_chann->path);
1981         g_dbus_unregister_interface(del_data->conn, path, HEALTH_CHANNEL);
1982         g_free(path);
1983
1984         reply = g_dbus_create_reply(del_data->msg, DBUS_TYPE_INVALID);
1985         g_dbus_send_message(del_data->conn, reply);
1986 }
1987
1988 static void hdp_continue_del_cb(gpointer user_data, GError *err)
1989 {
1990         struct hdp_tmp_dc_data *del_data = user_data;
1991         GError *gerr = NULL;
1992         DBusMessage *reply;
1993
1994         if (err != NULL) {
1995                 reply = g_dbus_create_error(del_data->msg,
1996                                         ERROR_INTERFACE ".HealthError",
1997                                         "%s", err->message);
1998                 g_dbus_send_message(del_data->conn, reply);
1999                 return;
2000         }
2001
2002         if (mcap_delete_mdl(del_data->hdp_chann->mdl, hdp_mdl_delete_cb,
2003                                                 hdp_tmp_dc_data_ref(del_data),
2004                                                 hdp_tmp_dc_data_destroy, &gerr))
2005                         return;
2006
2007         reply = g_dbus_create_error(del_data->msg,
2008                                                 ERROR_INTERFACE ".HealthError",
2009                                                 "%s", gerr->message);
2010 #ifdef __TIZEN_PATCH__
2011         g_dbus_send_message(del_data->conn, reply);
2012         g_error_free(gerr);
2013         hdp_tmp_dc_data_unref(del_data);
2014 #else
2015         hdp_tmp_dc_data_unref(del_data);
2016         g_error_free(gerr);
2017         g_dbus_send_message(del_data->conn, reply);
2018 #endif
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->conn = dbus_connection_ref(conn);
2045         del_data->hdp_chann = hdp_channel_ref(hdp_chan);
2046
2047         if (device->mcl_conn) {
2048                 if (mcap_delete_mdl(hdp_chan->mdl, hdp_mdl_delete_cb,
2049                                                 hdp_tmp_dc_data_ref(del_data),
2050                                                 hdp_tmp_dc_data_destroy, &err))
2051                         return NULL;
2052                 goto fail;
2053         }
2054
2055         if (hdp_establish_mcl(device, hdp_continue_del_cb,
2056                                                 hdp_tmp_dc_data_ref(del_data),
2057                                                 hdp_tmp_dc_data_destroy, &err))
2058                 return NULL;
2059
2060 fail:
2061         reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError",
2062                                                         "%s", err->message);
2063         hdp_tmp_dc_data_unref(del_data);
2064         g_error_free(err);
2065         return reply;
2066 }
2067
2068 static DBusMessage *device_get_properties(DBusConnection *conn,
2069                                         DBusMessage *msg, void *user_data)
2070 {
2071         struct hdp_device *device = user_data;
2072         DBusMessageIter iter, dict;
2073         DBusMessage *reply;
2074
2075         reply = dbus_message_new_method_return(msg);
2076         if (reply == NULL)
2077                 return NULL;
2078
2079         dbus_message_iter_init_append(reply, &iter);
2080
2081         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
2082                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
2083                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
2084                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
2085
2086         if (device->fr != NULL)
2087                 dict_append_entry(&dict, "MainChannel", DBUS_TYPE_OBJECT_PATH,
2088                                                         &device->fr->path);
2089
2090         dbus_message_iter_close_container(&iter, &dict);
2091
2092         return reply;
2093 }
2094
2095 static void health_device_destroy(void *data)
2096 {
2097         struct hdp_device *device = data;
2098
2099         DBG("Unregistered interface %s on path %s", HEALTH_DEVICE,
2100                                                 device_get_path(device->dev));
2101
2102         remove_channels(device);
2103         if (device->ndc != NULL) {
2104                 hdp_channel_unref(device->ndc);
2105                 device->ndc = NULL;
2106         }
2107
2108         devices = g_slist_remove(devices, device);
2109         health_device_unref(device);
2110 }
2111
2112 static const GDBusMethodTable health_device_methods[] = {
2113         { GDBUS_ASYNC_METHOD("Echo",
2114                         NULL, GDBUS_ARGS({ "value", "b" }), device_echo) },
2115         { GDBUS_ASYNC_METHOD("CreateChannel",
2116                         GDBUS_ARGS({ "application", "o" },
2117                                         { "configuration", "s" }),
2118                         GDBUS_ARGS({ "channel", "o" }),
2119                         device_create_channel) },
2120         { GDBUS_ASYNC_METHOD("DestroyChannel",
2121                         GDBUS_ARGS({ "channel", "o" }), NULL,
2122                         device_destroy_channel) },
2123         { GDBUS_METHOD("GetProperties",
2124                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
2125                         device_get_properties) },
2126         { }
2127 };
2128
2129 static const GDBusSignalTable health_device_signals[] = {
2130         { GDBUS_SIGNAL("ChannelConnected",
2131                         GDBUS_ARGS({ "channel", "o" })) },
2132         { GDBUS_SIGNAL("ChannelDeleted",
2133                         GDBUS_ARGS({ "channel", "o" })) },
2134         { GDBUS_SIGNAL("PropertyChanged",
2135                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
2136         { }
2137 };
2138
2139 static struct hdp_device *create_health_device(DBusConnection *conn,
2140                                                 struct btd_device *device)
2141 {
2142         struct btd_adapter *adapter = device_get_adapter(device);
2143         const gchar *path = device_get_path(device);
2144         struct hdp_device *dev;
2145         GSList *l;
2146
2147         if (device == NULL)
2148                 return NULL;
2149
2150         dev = g_new0(struct hdp_device, 1);
2151         dev->conn = dbus_connection_ref(conn);
2152         dev->dev = btd_device_ref(device);
2153         health_device_ref(dev);
2154
2155         l = g_slist_find_custom(adapters, adapter, cmp_adapter);
2156         if (l == NULL)
2157                 goto fail;
2158
2159         dev->hdp_adapter = l->data;
2160
2161         if (!g_dbus_register_interface(conn, path,
2162                                         HEALTH_DEVICE,
2163                                         health_device_methods,
2164                                         health_device_signals, NULL,
2165                                         dev, health_device_destroy)) {
2166                 error("D-Bus failed to register %s interface", HEALTH_DEVICE);
2167                 goto fail;
2168         }
2169
2170         DBG("Registered interface %s on path %s", HEALTH_DEVICE, path);
2171         return dev;
2172
2173 fail:
2174         health_device_unref(dev);
2175         return NULL;
2176 }
2177
2178 int hdp_device_register(DBusConnection *conn, struct btd_device *device)
2179 {
2180         struct hdp_device *hdev;
2181         GSList *l;
2182
2183         l = g_slist_find_custom(devices, device, cmp_device);
2184         if (l != NULL) {
2185                 hdev = l->data;
2186                 hdev->sdp_present = TRUE;
2187                 return 0;
2188         }
2189
2190         hdev = create_health_device(conn, device);
2191         if (hdev == NULL)
2192                 return -1;
2193
2194         hdev->sdp_present = TRUE;
2195
2196         devices = g_slist_prepend(devices, hdev);
2197         return 0;
2198 }
2199
2200 void hdp_device_unregister(struct btd_device *device)
2201 {
2202         struct hdp_device *hdp_dev;
2203         const char *path;
2204         GSList *l;
2205
2206         l = g_slist_find_custom(devices, device, cmp_device);
2207         if (l == NULL)
2208                 return;
2209
2210         hdp_dev = l->data;
2211         path = device_get_path(hdp_dev->dev);
2212         g_dbus_unregister_interface(hdp_dev->conn, path, HEALTH_DEVICE);
2213 }
2214
2215 int hdp_manager_start(DBusConnection *conn)
2216 {
2217         DBG("Starting Health manager");
2218
2219         if (!g_dbus_register_interface(conn, MANAGER_PATH,
2220                                         HEALTH_MANAGER,
2221                                         health_manager_methods, NULL, NULL,
2222                                         NULL, manager_path_unregister)) {
2223                 error("D-Bus failed to register %s interface", HEALTH_MANAGER);
2224                 return -1;
2225         }
2226
2227         connection = dbus_connection_ref(conn);
2228
2229         return 0;
2230 }
2231
2232 void hdp_manager_stop(void)
2233 {
2234         g_dbus_unregister_interface(connection, MANAGER_PATH, HEALTH_MANAGER);
2235
2236         dbus_connection_unref(connection);
2237         DBG("Stopped Health manager");
2238 }
2239
2240 struct hdp_device *health_device_ref(struct hdp_device *hdp_dev)
2241 {
2242         hdp_dev->ref++;
2243
2244         DBG("health_device_ref(%p): ref=%d", hdp_dev, hdp_dev->ref);
2245
2246         return hdp_dev;
2247 }
2248
2249 void health_device_unref(struct hdp_device *hdp_dev)
2250 {
2251         hdp_dev->ref--;
2252
2253         DBG("health_device_unref(%p): ref=%d", hdp_dev, hdp_dev->ref);
2254
2255         if (hdp_dev->ref > 0)
2256                 return;
2257
2258         free_health_device(hdp_dev);
2259 }