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