1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2006-2010 Nokia Corporation 6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel (at) holtmann.org> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25 #ifdef HAVE_CONFIG_H 26 #include <config.h> 27 #endif 28 29 #include <stdio.h> 30 #include <errno.h> 31 #include <stdlib.h> 32 #include <sys/socket.h> 33 #include <sys/ioctl.h> 34 35 #include <bluetooth/bluetooth.h> 36 #include <bluetooth/hci.h> 37 #include <bluetooth/hci_lib.h> 38 #include <bluetooth/sdp.h> 39 40 #include <glib.h> 41 #include <dbus/dbus.h> 42 #include <gdbus.h> 43 44 #include "log.h" 45 46 #include "hcid.h" 47 #include "adapter.h" 48 #include "device.h" 49 #include "agent.h" 50 51 #define REQUEST_TIMEOUT (60 * 1000) /* 60 seconds */ 52 53 typedef enum { 54 AGENT_REQUEST_PASSKEY, 55 AGENT_REQUEST_CONFIRMATION, 56 AGENT_REQUEST_PINCODE, 57 AGENT_REQUEST_AUTHORIZE, 58 AGENT_REQUEST_CONFIRM_MODE, 59 AGENT_REQUEST_OOB_AVAILABILITY, 60 AGENT_REQUEST_OOB_DATA, 61 AGENT_REQUEST_PAIRING_CONSENT, 62 } agent_request_type_t; 63 64 struct agent { 65 struct btd_adapter *adapter; 66 char *name; 67 char *path; 68 uint8_t capability; 69 gboolean oob; 70 struct agent_request *request; 71 int exited; 72 agent_remove_cb remove_cb; 73 void *remove_cb_data; 74 guint listener_id; 75 }; 76 77 struct agent_request { 78 agent_request_type_t type; 79 struct agent *agent; 80 DBusMessage *msg; 81 DBusPendingCall *call; 82 void *cb; 83 void *user_data; 84 GDestroyNotify destroy; 85 }; 86 87 static DBusConnection *connection = NULL; 88 89 static int request_fallback(struct agent_request *req, 90 DBusPendingCallNotifyFunction function); 91 92 static void agent_release(struct agent *agent) 93 { 94 DBusMessage *message; 95 96 DBG("Releasing agent %s, %s", agent->name, agent->path); 97 98 if (agent->request) 99 agent_cancel(agent); 100 101 message = dbus_message_new_method_call(agent->name, agent->path, 102 "org.bluez.Agent", "Release"); 103 if (message == NULL) { 104 error("Couldn't allocate D-Bus message"); 105 return; 106 } 107 108 g_dbus_send_message(connection, message); 109 } 110 111 static int send_cancel_request(struct agent_request *req) 112 { 113 DBusMessage *message; 114 115 message = dbus_message_new_method_call(req->agent->name, req->agent->path, 116 "org.bluez.Agent", "Cancel"); 117 if (message == NULL) { 118 error("Couldn't allocate D-Bus message"); 119 return -ENOMEM; 120 } 121 122 g_dbus_send_message(connection, message); 123 124 return 0; 125 } 126 127 static void agent_request_free(struct agent_request *req, gboolean destroy) 128 { 129 if (req->msg) 130 dbus_message_unref(req->msg); 131 if (req->call) 132 dbus_pending_call_unref(req->call); 133 if (req->agent && req->agent->request) 134 req->agent->request = NULL; 135 if (destroy && req->destroy) 136 req->destroy(req->user_data); 137 g_free(req); 138 } 139 140 static void agent_exited(DBusConnection *conn, void *user_data) 141 { 142 struct agent *agent = user_data; 143 144 DBG("Agent exited without calling Unregister"); 145 146 agent->exited = TRUE; 147 148 agent_free(agent); 149 } 150 151 void agent_free(struct agent *agent) 152 { 153 if (!agent) 154 return; 155 156 if (agent->remove_cb) 157 agent->remove_cb(agent, agent->remove_cb_data); 158 159 if (agent->request) { 160 DBusError err; 161 agent_pincode_cb pincode_cb; 162 agent_cb cb; 163 164 dbus_error_init(&err); 165 dbus_set_error_const(&err, "org.bluez.Error.Failed", "Canceled"); 166 167 switch (agent->request->type) { 168 case AGENT_REQUEST_PINCODE: 169 pincode_cb = agent->request->cb; 170 pincode_cb(agent, &err, NULL, agent->request->user_data); 171 break; 172 default: 173 cb = agent->request->cb; 174 cb(agent, &err, agent->request->user_data); 175 } 176 177 dbus_error_free(&err); 178 179 agent_cancel(agent); 180 } 181 182 if (!agent->exited) { 183 g_dbus_remove_watch(connection, agent->listener_id); 184 agent_release(agent); 185 } 186 187 g_free(agent->name); 188 g_free(agent->path); 189 190 g_free(agent); 191 } 192 193 struct agent *agent_create(struct btd_adapter *adapter, const char *name, 194 const char *path, uint8_t capability, 195 gboolean oob, agent_remove_cb cb, 196 void *remove_cb_data) 197 { 198 struct agent *agent; 199 200 agent = g_new0(struct agent, 1); 201 202 agent->adapter = adapter; 203 agent->name = g_strdup(name); 204 agent->path = g_strdup(path); 205 agent->capability = capability; 206 agent->oob = oob; 207 agent->remove_cb = cb; 208 agent->remove_cb_data = remove_cb_data; 209 210 agent->listener_id = g_dbus_add_disconnect_watch(connection, name, 211 agent_exited, agent, 212 NULL); 213 214 return agent; 215 } 216 217 static struct agent_request *agent_request_new(struct agent *agent, 218 agent_request_type_t type, 219 void *cb, 220 void *user_data, 221 GDestroyNotify destroy) 222 { 223 struct agent_request *req; 224 225 req = g_new0(struct agent_request, 1); 226 227 req->agent = agent; 228 req->type = type; 229 req->cb = cb; 230 req->user_data = user_data; 231 req->destroy = destroy; 232 233 return req; 234 } 235 236 int agent_cancel(struct agent *agent) 237 { 238 if (!agent->request) 239 return -EINVAL; 240 241 if (agent->request->call) 242 dbus_pending_call_cancel(agent->request->call); 243 244 if (!agent->exited) 245 send_cancel_request(agent->request); 246 247 agent_request_free(agent->request, TRUE); 248 agent->request = NULL; 249 250 return 0; 251 } 252 253 static void simple_agent_reply(DBusPendingCall *call, void *user_data) 254 { 255 struct agent_request *req = user_data; 256 struct agent *agent = req->agent; 257 DBusMessage *message; 258 DBusError err; 259 agent_cb cb = req->cb; 260 261 /* steal_reply will always return non-NULL since the callback 262 * is only called after a reply has been received */ 263 message = dbus_pending_call_steal_reply(call); 264 265 dbus_error_init(&err); 266 if (dbus_set_error_from_message(&err, message)) { 267 if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || 268 g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && 269 request_fallback(req, simple_agent_reply) == 0) { 270 dbus_error_free(&err); 271 return; 272 } 273 274 error("Agent replied with an error: %s, %s", 275 err.name, err.message); 276 277 cb(agent, &err, req->user_data); 278 279 if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) { 280 agent_cancel(agent); 281 dbus_message_unref(message); 282 dbus_error_free(&err); 283 return; 284 } 285 286 dbus_error_free(&err); 287 goto done; 288 } 289 290 dbus_error_init(&err); 291 if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) { 292 error("Wrong reply signature: %s", err.message); 293 cb(agent, &err, req->user_data); 294 dbus_error_free(&err); 295 goto done; 296 } 297 298 cb(agent, NULL, req->user_data); 299 done: 300 dbus_message_unref(message); 301 302 agent->request = NULL; 303 agent_request_free(req, TRUE); 304 } 305 306 static int agent_call_authorize(struct agent_request *req, 307 const char *device_path, 308 const char *uuid) 309 { 310 struct agent *agent = req->agent; 311 312 req->msg = dbus_message_new_method_call(agent->name, agent->path, 313 "org.bluez.Agent", "Authorize"); 314 if (!req->msg) { 315 error("Couldn't allocate D-Bus message"); 316 return -ENOMEM; 317 } 318 319 dbus_message_append_args(req->msg, 320 DBUS_TYPE_OBJECT_PATH, &device_path, 321 DBUS_TYPE_STRING, &uuid, 322 DBUS_TYPE_INVALID); 323 324 if (dbus_connection_send_with_reply(connection, req->msg, 325 &req->call, REQUEST_TIMEOUT) == FALSE) { 326 error("D-Bus send failed"); 327 return -EIO; 328 } 329 330 dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); 331 return 0; 332 } 333 334 int agent_authorize(struct agent *agent, 335 const char *path, 336 const char *uuid, 337 agent_cb cb, 338 void *user_data, 339 GDestroyNotify destroy) 340 { 341 struct agent_request *req; 342 int err; 343 344 if (agent->request) 345 return -EBUSY; 346 347 req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE, cb, 348 user_data, destroy); 349 350 err = agent_call_authorize(req, path, uuid); 351 if (err < 0) { 352 agent_request_free(req, FALSE); 353 return -ENOMEM; 354 } 355 356 agent->request = req; 357 358 DBG("authorize request was sent for %s", path); 359 360 return 0; 361 } 362 363 364 static int agent_call_oob_availability(struct agent_request *req, 365 const char *device_path) 366 { 367 struct agent *agent = req->agent; 368 369 req->msg = dbus_message_new_method_call(agent->name, agent->path, 370 "org.bluez.Agent", "OutOfBandAvailable"); 371 if (!req->msg) { 372 error("Couldn't allocate D-Bus message"); 373 return -ENOMEM; 374 } 375 376 dbus_message_append_args(req->msg, 377 DBUS_TYPE_OBJECT_PATH, &device_path, 378 DBUS_TYPE_INVALID); 379 380 if (dbus_connection_send_with_reply(connection, req->msg, 381 &req->call, REQUEST_TIMEOUT) == FALSE) { 382 error("D-Bus send failed"); 383 return -EIO; 384 } 385 386 dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); 387 return 0; 388 } 389 390 int agent_request_oob_availability(struct agent *agent, 391 const char *path, 392 agent_cb cb, 393 void *user_data, 394 GDestroyNotify destroy) 395 { 396 struct agent_request *req; 397 int err; 398 399 if (agent->request) 400 return -EBUSY; 401 402 req = agent_request_new(agent, AGENT_REQUEST_OOB_AVAILABILITY, cb, 403 user_data, destroy); 404 405 err = agent_call_oob_availability(req, path); 406 if (err < 0) { 407 agent_request_free(req, FALSE); 408 return -ENOMEM; 409 } 410 411 agent->request = req; 412 413 DBG("oob availability request was sent for %s", path); 414 415 return 0; 416 } 417 418 static void pincode_reply(DBusPendingCall *call, void *user_data) 419 { 420 struct agent_request *req = user_data; 421 struct agent *agent = req->agent; 422 struct btd_adapter *adapter = agent->adapter; 423 agent_pincode_cb cb = req->cb; 424 DBusMessage *message; 425 DBusError err; 426 bdaddr_t sba; 427 size_t len; 428 char *pin; 429 430 adapter_get_address(adapter, &sba); 431 432 /* steal_reply will always return non-NULL since the callback 433 * is only called after a reply has been received */ 434 message = dbus_pending_call_steal_reply(call); 435 436 dbus_error_init(&err); 437 if (dbus_set_error_from_message(&err, message)) { 438 if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || 439 g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && 440 request_fallback(req, pincode_reply) == 0) { 441 dbus_error_free(&err); 442 return; 443 } 444 445 error("Agent replied with an error: %s, %s", 446 err.name, err.message); 447 448 cb(agent, &err, NULL, req->user_data); 449 dbus_error_free(&err); 450 goto done; 451 } 452 453 dbus_error_init(&err); 454 if (!dbus_message_get_args(message, &err, 455 DBUS_TYPE_STRING, &pin, 456 DBUS_TYPE_INVALID)) { 457 error("Wrong passkey reply signature: %s", err.message); 458 cb(agent, &err, NULL, req->user_data); 459 dbus_error_free(&err); 460 goto done; 461 } 462 463 len = strlen(pin); 464 465 dbus_error_init(&err); 466 if (len > 16 || len < 1) { 467 error("Invalid passkey length from handler"); 468 dbus_set_error_const(&err, "org.bluez.Error.InvalidArgs", 469 "Invalid passkey length"); 470 cb(agent, &err, NULL, req->user_data); 471 dbus_error_free(&err); 472 goto done; 473 } 474 475 set_pin_length(&sba, len); 476 477 cb(agent, NULL, pin, req->user_data); 478 479 done: 480 if (message) 481 dbus_message_unref(message); 482 483 dbus_pending_call_cancel(req->call); 484 agent->request = NULL; 485 agent_request_free(req, TRUE); 486 } 487 488 static int pincode_request_new(struct agent_request *req, const char *device_path, 489 dbus_bool_t numeric) 490 { 491 struct agent *agent = req->agent; 492 493 req->msg = dbus_message_new_method_call(agent->name, agent->path, 494 "org.bluez.Agent", "RequestPinCode"); 495 if (req->msg == NULL) { 496 error("Couldn't allocate D-Bus message"); 497 return -ENOMEM; 498 } 499 500 dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, 501 DBUS_TYPE_INVALID); 502 503 if (dbus_connection_send_with_reply(connection, req->msg, 504 &req->call, REQUEST_TIMEOUT) == FALSE) { 505 error("D-Bus send failed"); 506 return -EIO; 507 } 508 509 dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL); 510 return 0; 511 } 512 513 int agent_request_pincode(struct agent *agent, struct btd_device *device, 514 agent_pincode_cb cb, void *user_data, 515 GDestroyNotify destroy) 516 { 517 struct agent_request *req; 518 const gchar *dev_path = device_get_path(device); 519 int err; 520 521 if (agent->request) 522 return -EBUSY; 523 524 req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb, 525 user_data, destroy); 526 527 err = pincode_request_new(req, dev_path, FALSE); 528 if (err < 0) 529 goto failed; 530 531 agent->request = req; 532 533 return 0; 534 535 failed: 536 g_free(req); 537 return err; 538 } 539 540 static int confirm_mode_change_request_new(struct agent_request *req, 541 const char *mode) 542 { 543 struct agent *agent = req->agent; 544 545 req->msg = dbus_message_new_method_call(agent->name, agent->path, 546 "org.bluez.Agent", "ConfirmModeChange"); 547 if (req->msg == NULL) { 548 error("Couldn't allocate D-Bus message"); 549 return -ENOMEM; 550 } 551 552 dbus_message_append_args(req->msg, 553 DBUS_TYPE_STRING, &mode, 554 DBUS_TYPE_INVALID); 555 556 if (dbus_connection_send_with_reply(connection, req->msg, 557 &req->call, REQUEST_TIMEOUT) == FALSE) { 558 error("D-Bus send failed"); 559 return -EIO; 560 } 561 562 dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); 563 return 0; 564 } 565 566 int agent_confirm_mode_change(struct agent *agent, const char *new_mode, 567 agent_cb cb, void *user_data, 568 GDestroyNotify destroy) 569 { 570 struct agent_request *req; 571 int err; 572 573 if (agent->request) 574 return -EBUSY; 575 576 DBG("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s", 577 agent->name, agent->path, new_mode); 578 579 req = agent_request_new(agent, AGENT_REQUEST_CONFIRM_MODE, 580 cb, user_data, destroy); 581 582 err = confirm_mode_change_request_new(req, new_mode); 583 if (err < 0) 584 goto failed; 585 586 agent->request = req; 587 588 return 0; 589 590 failed: 591 agent_request_free(req, FALSE); 592 return err; 593 } 594 595 static void passkey_reply(DBusPendingCall *call, void *user_data) 596 { 597 struct agent_request *req = user_data; 598 struct agent *agent = req->agent; 599 agent_passkey_cb cb = req->cb; 600 DBusMessage *message; 601 DBusError err; 602 uint32_t passkey; 603 604 /* steal_reply will always return non-NULL since the callback 605 * is only called after a reply has been received */ 606 message = dbus_pending_call_steal_reply(call); 607 608 dbus_error_init(&err); 609 if (dbus_set_error_from_message(&err, message)) { 610 if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || 611 g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && 612 request_fallback(req, passkey_reply) == 0) { 613 dbus_error_free(&err); 614 return; 615 } 616 617 error("Agent replied with an error: %s, %s", 618 err.name, err.message); 619 cb(agent, &err, 0, req->user_data); 620 dbus_error_free(&err); 621 goto done; 622 } 623 624 dbus_error_init(&err); 625 if (!dbus_message_get_args(message, &err, 626 DBUS_TYPE_UINT32, &passkey, 627 DBUS_TYPE_INVALID)) { 628 error("Wrong passkey reply signature: %s", err.message); 629 cb(agent, &err, 0, req->user_data); 630 dbus_error_free(&err); 631 goto done; 632 } 633 634 cb(agent, NULL, passkey, req->user_data); 635 636 done: 637 if (message) 638 dbus_message_unref(message); 639 640 dbus_pending_call_cancel(req->call); 641 agent->request = NULL; 642 agent_request_free(req, TRUE); 643 } 644 645 static int passkey_request_new(struct agent_request *req, 646 const char *device_path) 647 { 648 struct agent *agent = req->agent; 649 650 req->msg = dbus_message_new_method_call(agent->name, agent->path, 651 "org.bluez.Agent", "RequestPasskey"); 652 if (req->msg == NULL) { 653 error("Couldn't allocate D-Bus message"); 654 return -ENOMEM; 655 } 656 657 dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, 658 DBUS_TYPE_INVALID); 659 660 if (dbus_connection_send_with_reply(connection, req->msg, 661 &req->call, REQUEST_TIMEOUT) == FALSE) { 662 error("D-Bus send failed"); 663 return -EIO; 664 } 665 666 dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL); 667 return 0; 668 } 669 670 int agent_request_passkey(struct agent *agent, struct btd_device *device, 671 agent_passkey_cb cb, void *user_data, 672 GDestroyNotify destroy) 673 { 674 struct agent_request *req; 675 const gchar *dev_path = device_get_path(device); 676 int err; 677 678 if (agent->request) 679 return -EBUSY; 680 681 DBG("Calling Agent.RequestPasskey: name=%s, path=%s", 682 agent->name, agent->path); 683 684 req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb, 685 user_data, destroy); 686 687 err = passkey_request_new(req, dev_path); 688 if (err < 0) 689 goto failed; 690 691 agent->request = req; 692 693 return 0; 694 695 failed: 696 agent_request_free(req, FALSE); 697 return err; 698 } 699 700 static void oob_data_reply(DBusPendingCall *call, void *user_data) 701 { 702 struct agent_request *req = user_data; 703 struct agent *agent = req->agent; 704 agent_oob_data_cb cb = req->cb; 705 DBusMessage *message; 706 DBusError err; 707 uint8_t *hash_ptr, *r_ptr; 708 uint8_t hash_len, r_len; 709 710 /* steal_reply will always return non-NULL since the callback 711 * is only called after a reply has been received */ 712 message = dbus_pending_call_steal_reply(call); 713 714 dbus_error_init(&err); 715 if (dbus_set_error_from_message(&err, message)) { 716 if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || 717 g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && 718 request_fallback(req, oob_data_reply) == 0) { 719 dbus_error_free(&err); 720 return; 721 } 722 723 error("Agent replied with an error: %s, %s", 724 err.name, err.message); 725 cb(agent, &err, 0, 0, req->user_data); 726 dbus_error_free(&err); 727 goto done; 728 } 729 730 if (!dbus_message_get_args(message, &err, 731 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash_ptr, &hash_len, 732 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &r_ptr, &r_len, 733 DBUS_TYPE_INVALID)) { 734 error("Wrong OOB data reply signature: %s", err.message); 735 cb(agent, &err, 0, 0, req->user_data); 736 dbus_error_free(&err); 737 goto done; 738 } 739 740 cb(agent, NULL, hash_ptr, r_ptr, req->user_data); 741 742 done: 743 if (message) 744 dbus_message_unref(message); 745 746 dbus_pending_call_cancel(req->call); 747 agent->request = NULL; 748 agent_request_free(req, TRUE); 749 } 750 751 static int oob_data_request_new(struct agent_request *req, 752 const char *device_path) 753 { 754 struct agent *agent = req->agent; 755 756 req->msg = dbus_message_new_method_call(agent->name, agent->path, 757 "org.bluez.Agent", "RequestOobData"); 758 if (req->msg == NULL) { 759 error("Couldn't allocate D-Bus message"); 760 return -ENOMEM; 761 } 762 763 dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, 764 DBUS_TYPE_INVALID); 765 766 if (dbus_connection_send_with_reply(connection, req->msg, 767 &req->call, REQUEST_TIMEOUT) == FALSE) { 768 error("D-Bus send failed"); 769 return -EIO; 770 } 771 772 dbus_pending_call_set_notify(req->call, oob_data_reply, req, NULL); 773 return 0; 774 } 775 776 int agent_request_oob_data(struct agent *agent, struct btd_device *device, 777 agent_oob_data_cb cb, void *user_data, 778 GDestroyNotify destroy) 779 { 780 struct agent_request *req; 781 const gchar *dev_path = device_get_path(device); 782 int err; 783 784 if (agent->request) 785 return -EBUSY; 786 787 DBG("Calling Agent.RequestOobData: name=%s, path=%s", 788 agent->name, agent->path); 789 790 req = agent_request_new(agent, AGENT_REQUEST_OOB_DATA, cb, 791 user_data, destroy); 792 793 err = oob_data_request_new(req, dev_path); 794 if (err < 0) 795 goto failed; 796 797 agent->request = req; 798 799 return 0; 800 801 failed: 802 agent_request_free(req, FALSE); 803 return err; 804 } 805 806 static int confirmation_request_new(struct agent_request *req, 807 const char *device_path, 808 uint32_t passkey) 809 { 810 struct agent *agent = req->agent; 811 812 req->msg = dbus_message_new_method_call(agent->name, agent->path, 813 "org.bluez.Agent", "RequestConfirmation"); 814 if (req->msg == NULL) { 815 error("Couldn't allocate D-Bus message"); 816 return -ENOMEM; 817 } 818 819 dbus_message_append_args(req->msg, 820 DBUS_TYPE_OBJECT_PATH, &device_path, 821 DBUS_TYPE_UINT32, &passkey, 822 DBUS_TYPE_INVALID); 823 824 if (dbus_connection_send_with_reply(connection, req->msg, 825 &req->call, REQUEST_TIMEOUT) == FALSE) { 826 error("D-Bus send failed"); 827 return -EIO; 828 } 829 830 dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); 831 832 return 0; 833 } 834 835 int agent_request_confirmation(struct agent *agent, struct btd_device *device, 836 uint32_t passkey, agent_cb cb, 837 void *user_data, GDestroyNotify destroy) 838 { 839 struct agent_request *req; 840 const gchar *dev_path = device_get_path(device); 841 int err; 842 843 if (agent->request) 844 return -EBUSY; 845 846 DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u", 847 agent->name, agent->path, passkey); 848 849 req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb, 850 user_data, destroy); 851 852 err = confirmation_request_new(req, dev_path, passkey); 853 if (err < 0) 854 goto failed; 855 856 agent->request = req; 857 858 return 0; 859 860 failed: 861 agent_request_free(req, FALSE); 862 return err; 863 } 864 865 static int pairing_consent_request_new(struct agent_request *req, 866 const char *device_path) 867 { 868 struct agent *agent = req->agent; 869 870 req->msg = dbus_message_new_method_call(agent->name, agent->path, 871 "org.bluez.Agent", "RequestPairingConsent"); 872 if (req->msg == NULL) { 873 error("Couldn't allocate D-Bus message"); 874 return -ENOMEM; 875 } 876 877 dbus_message_append_args(req->msg, 878 DBUS_TYPE_OBJECT_PATH, &device_path, 879 DBUS_TYPE_INVALID); 880 881 if (dbus_connection_send_with_reply(connection, req->msg, 882 &req->call, REQUEST_TIMEOUT) == FALSE) { 883 error("D-Bus send failed"); 884 return -EIO; 885 } 886 887 dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); 888 889 return 0; 890 } 891 892 int agent_request_pairing_consent(struct agent *agent, struct btd_device *device, 893 agent_cb cb, void *user_data, 894 GDestroyNotify destroy) 895 { 896 struct agent_request *req; 897 const gchar *dev_path = device_get_path(device); 898 int err; 899 900 if (agent->request) 901 return -EBUSY; 902 903 DBG("Calling Agent.RequestPairingConsent: name=%s, path=%s", 904 agent->name, agent->path); 905 906 req = agent_request_new(agent, AGENT_REQUEST_PAIRING_CONSENT, cb, 907 user_data, destroy); 908 909 err = pairing_consent_request_new(req, dev_path); 910 if (err < 0) 911 goto failed; 912 913 agent->request = req; 914 915 return 0; 916 917 failed: 918 agent_request_free(req, FALSE); 919 return err; 920 } 921 922 static int request_fallback(struct agent_request *req, 923 DBusPendingCallNotifyFunction function) 924 { 925 struct btd_adapter *adapter = req->agent->adapter; 926 struct agent *adapter_agent = adapter_get_agent(adapter); 927 DBusMessage *msg; 928 929 if (req->agent == adapter_agent || adapter_agent == NULL) 930 return -EINVAL; 931 932 dbus_pending_call_cancel(req->call); 933 934 msg = dbus_message_copy(req->msg); 935 936 dbus_message_set_destination(msg, adapter_agent->name); 937 dbus_message_set_path(msg, adapter_agent->path); 938 939 if (dbus_connection_send_with_reply(connection, msg, 940 &req->call, REQUEST_TIMEOUT) == FALSE) { 941 error("D-Bus send failed"); 942 dbus_message_unref(msg); 943 return -EIO; 944 } 945 946 req->agent->request = NULL; 947 req->agent = adapter_agent; 948 req->agent->request = req; 949 950 dbus_message_unref(req->msg); 951 req->msg = msg; 952 953 dbus_pending_call_set_notify(req->call, function, req, NULL); 954 955 return 0; 956 } 957 958 int agent_display_passkey(struct agent *agent, struct btd_device *device, 959 uint32_t passkey) 960 { 961 DBusMessage *message; 962 const gchar *dev_path = device_get_path(device); 963 964 message = dbus_message_new_method_call(agent->name, agent->path, 965 "org.bluez.Agent", "DisplayPasskey"); 966 if (!message) { 967 error("Couldn't allocate D-Bus message"); 968 return -1; 969 } 970 971 dbus_message_append_args(message, 972 DBUS_TYPE_OBJECT_PATH, &dev_path, 973 DBUS_TYPE_UINT32, &passkey, 974 DBUS_TYPE_INVALID); 975 976 if (!g_dbus_send_message(connection, message)) { 977 error("D-Bus send failed"); 978 dbus_message_unref(message); 979 return -1; 980 } 981 982 return 0; 983 } 984 985 uint8_t agent_get_io_capability(struct agent *agent) 986 { 987 return agent->capability; 988 } 989 990 gboolean agent_get_oob_capability(struct agent *agent) 991 { 992 return agent->oob; 993 } 994 995 gboolean agent_matches(struct agent *agent, const char *name, const char *path) 996 { 997 if (g_str_equal(agent->name, name) && g_str_equal(agent->path, path)) 998 return TRUE; 999 1000 return FALSE; 1001 } 1002 1003 gboolean agent_is_busy(struct agent *agent, void *user_data) 1004 { 1005 if (!agent->request) 1006 return FALSE; 1007 1008 if (user_data && user_data != agent->request->user_data) 1009 return FALSE; 1010 1011 return TRUE; 1012 } 1013 1014 void agent_exit(void) 1015 { 1016 dbus_connection_unref(connection); 1017 connection = NULL; 1018 } 1019 1020 void agent_init(void) 1021 { 1022 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); 1023 } 1024