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