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