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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1620 static void delete_mdl_cb(GError *err, gpointer data) 1621 { 1622 if (err) 1623 error("Deleting error: %s", err->message); 1624 } 1625 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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