mgmtops.c revision 27a311476a53c72ac06d6cdc3cffbef14a0caba7
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2010 Nokia Corporation 6 * Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27 28#include <stdio.h> 29#include <errno.h> 30#include <unistd.h> 31#include <stdlib.h> 32#include <sys/types.h> 33#include <sys/ioctl.h> 34#include <sys/wait.h> 35 36#include <glib.h> 37 38#include <bluetooth/bluetooth.h> 39#include <bluetooth/hci.h> 40#include <bluetooth/mgmt.h> 41 42#include "plugin.h" 43#include "log.h" 44#include "adapter.h" 45#include "manager.h" 46#include "device.h" 47#include "event.h" 48 49#define MGMT_BUF_SIZE 1024 50 51static int max_index = -1; 52static struct controller_info { 53 gboolean valid; 54 gboolean notified; 55 uint8_t type; 56 bdaddr_t bdaddr; 57 uint8_t features[8]; 58 uint8_t dev_class[3]; 59 uint16_t manufacturer; 60 uint8_t hci_ver; 61 uint16_t hci_rev; 62 gboolean enabled; 63 gboolean discoverable; 64 gboolean pairable; 65 uint8_t sec_mode; 66} *controllers = NULL; 67 68static int mgmt_sock = -1; 69static guint mgmt_watch = 0; 70 71static uint8_t mgmt_version = 0; 72static uint16_t mgmt_revision = 0; 73 74static void read_version_complete(int sk, void *buf, size_t len) 75{ 76 struct mgmt_hdr hdr; 77 struct mgmt_rp_read_version *rp = buf; 78 79 if (len < sizeof(*rp)) { 80 error("Too small read version complete event"); 81 return; 82 } 83 84 mgmt_revision = btohs(bt_get_unaligned(&rp->revision)); 85 mgmt_version = rp->version; 86 87 DBG("version %u revision %u", mgmt_version, mgmt_revision); 88 89 memset(&hdr, 0, sizeof(hdr)); 90 hdr.opcode = MGMT_OP_READ_INDEX_LIST; 91 if (write(sk, &hdr, sizeof(hdr)) < 0) 92 error("Unable to read controller index list: %s (%d)", 93 strerror(errno), errno); 94} 95 96static void add_controller(uint16_t index) 97{ 98 if (index > max_index) { 99 size_t size = sizeof(struct controller_info) * (index + 1); 100 max_index = index; 101 controllers = g_realloc(controllers, size); 102 } 103 104 memset(&controllers[index], 0, sizeof(struct controller_info)); 105 106 controllers[index].valid = TRUE; 107 108 DBG("Added controller %u", index); 109} 110 111static void read_info(int sk, uint16_t index) 112{ 113 char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_read_info)]; 114 struct mgmt_hdr *hdr = (void *) buf; 115 struct mgmt_cp_read_info *cp = (void *) &buf[sizeof(*hdr)]; 116 117 memset(buf, 0, sizeof(buf)); 118 hdr->opcode = MGMT_OP_READ_INFO; 119 hdr->len = htobs(sizeof(*cp)); 120 121 cp->index = htobs(index); 122 123 if (write(sk, buf, sizeof(buf)) < 0) 124 error("Unable to send read_info command: %s (%d)", 125 strerror(errno), errno); 126} 127 128static void mgmt_index_added(int sk, void *buf, size_t len) 129{ 130 struct mgmt_ev_index_added *ev = buf; 131 uint16_t index; 132 133 if (len < sizeof(*ev)) { 134 error("Too small index added event"); 135 return; 136 } 137 138 index = btohs(bt_get_unaligned(&ev->index)); 139 140 add_controller(index); 141 read_info(sk, index); 142} 143 144static void remove_controller(uint16_t index) 145{ 146 if (index > max_index) 147 return; 148 149 if (!controllers[index].valid) 150 return; 151 152 btd_manager_unregister_adapter(index); 153 154 memset(&controllers[index], 0, sizeof(struct controller_info)); 155 156 DBG("Removed controller %u", index); 157} 158 159static void mgmt_index_removed(int sk, void *buf, size_t len) 160{ 161 struct mgmt_ev_index_removed *ev = buf; 162 uint16_t index; 163 164 if (len < sizeof(*ev)) { 165 error("Too small index removed event"); 166 return; 167 } 168 169 index = btohs(bt_get_unaligned(&ev->index)); 170 171 remove_controller(index); 172} 173 174static void mgmt_powered(int sk, void *buf, size_t len) 175{ 176 struct btd_adapter *adapter; 177 struct mgmt_ev_powered *ev = buf; 178 uint16_t index; 179 180 if (len < sizeof(*ev)) { 181 error("Too small powered event"); 182 return; 183 } 184 185 index = btohs(bt_get_unaligned(&ev->index)); 186 187 if (index > max_index) { 188 DBG("Ignoring powered event for unknown controller %u", index); 189 return; 190 } 191 192 controllers[index].enabled = ev->powered; 193 194 DBG("Controller %u powered %s", index, ev->powered ? "on" : "off"); 195 196 adapter = manager_find_adapter(&controllers[index].bdaddr); 197 if (adapter == NULL) { 198 DBG("Adapter not found"); 199 return; 200 } 201 202 if (ev->powered) 203 btd_adapter_start(adapter); 204 else 205 btd_adapter_stop(adapter); 206} 207 208static void read_index_list_complete(int sk, void *buf, size_t len) 209{ 210 struct mgmt_rp_read_index_list *rp = buf; 211 uint16_t num; 212 int i; 213 214 if (len < sizeof(*rp)) { 215 error("Too small read index list complete event"); 216 return; 217 } 218 219 num = btohs(bt_get_unaligned(&rp->num_controllers)); 220 221 if (num * sizeof(uint16_t) + sizeof(*rp) != len) { 222 error("Incorrect packet size for index list event"); 223 return; 224 } 225 226 for (i = 0; i < num; i++) { 227 uint16_t index; 228 229 index = btohs(bt_get_unaligned(&rp->index[i])); 230 231 add_controller(index); 232 read_info(sk, index); 233 } 234} 235 236static int mgmt_power_off(int index) 237{ 238 char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_power_off)]; 239 struct mgmt_hdr *hdr = (void *) buf; 240 struct mgmt_cp_power_off *cp = (void *) &buf[sizeof(*hdr)]; 241 242 DBG("index %d", index); 243 244 memset(buf, 0, sizeof(buf)); 245 hdr->opcode = MGMT_OP_POWER_OFF; 246 hdr->len = htobs(sizeof(*cp)); 247 248 cp->index = htobs(index); 249 250 if (write(mgmt_sock, buf, sizeof(buf)) < 0) 251 return -errno; 252 253 return 0; 254} 255 256static int mgmt_set_discoverable(int index, gboolean discoverable) 257{ 258 DBG("index %d discoverable %d", index, discoverable); 259 return -ENOSYS; 260} 261 262static int mgmt_set_pairable(int index, gboolean pairable) 263{ 264 DBG("index %d pairable %d", index, pairable); 265 return -ENOSYS; 266} 267 268static void read_info_complete(int sk, void *buf, size_t len) 269{ 270 struct mgmt_rp_read_info *rp = buf; 271 struct controller_info *info; 272 struct btd_adapter *adapter; 273 uint8_t mode; 274 gboolean pairable, discoverable; 275 uint16_t index; 276 char addr[18]; 277 278 if (len < sizeof(*rp)) { 279 error("Too small read info complete event"); 280 return; 281 } 282 283 index = btohs(bt_get_unaligned(&rp->index)); 284 if (index > max_index) { 285 error("Unexpected index %u in read info complete", index); 286 return; 287 } 288 289 info = &controllers[index]; 290 info->type = rp->type; 291 info->enabled = rp->powered; 292 info->discoverable = rp->discoverable; 293 info->pairable = rp->pairable; 294 info->sec_mode = rp->sec_mode; 295 bacpy(&info->bdaddr, &rp->bdaddr); 296 memcpy(info->dev_class, rp->dev_class, 3); 297 memcpy(info->features, rp->features, 8); 298 info->manufacturer = btohs(bt_get_unaligned(&rp->manufacturer)); 299 info->hci_ver = rp->hci_ver; 300 info->hci_rev = btohs(bt_get_unaligned(&rp->hci_rev)); 301 302 ba2str(&info->bdaddr, addr); 303 DBG("hci%u type %u addr %s", index, info->type, addr); 304 DBG("hci%u class 0x%02x%02x%02x", index, 305 info->dev_class[2], info->dev_class[1], info->dev_class[0]); 306 DBG("hci%u manufacturer %d HCI ver %d:%d", index, info->manufacturer, 307 info->hci_ver, info->hci_rev); 308 DBG("hci%u enabled %u discoverable %u pairable %u sec_mode %u", index, 309 info->enabled, info->discoverable, 310 info->pairable, info->sec_mode); 311 312 adapter = btd_manager_register_adapter(index); 313 if (adapter == NULL) { 314 error("mgmtops: unable to register adapter"); 315 return; 316 } 317 318 btd_adapter_get_state(adapter, &mode, NULL, &pairable); 319 if (mode == MODE_OFF) { 320 mgmt_power_off(index); 321 return; 322 } 323 324 discoverable = (mode == MODE_DISCOVERABLE); 325 326 if (info->discoverable != discoverable) 327 mgmt_set_discoverable(index, discoverable); 328 329 if (info->pairable != pairable) 330 mgmt_set_pairable(index, pairable); 331 332 if (info->enabled) 333 btd_adapter_start(adapter); 334 335 btd_adapter_unref(adapter); 336} 337 338static void mgmt_cmd_complete(int sk, void *buf, size_t len) 339{ 340 struct mgmt_ev_cmd_complete *ev = buf; 341 uint16_t opcode; 342 343 DBG(""); 344 345 if (len < sizeof(*ev)) { 346 error("Too small management command complete event packet"); 347 return; 348 } 349 350 opcode = btohs(bt_get_unaligned(&ev->opcode)); 351 352 switch (opcode) { 353 case MGMT_OP_READ_VERSION: 354 read_version_complete(sk, ev->data, len - sizeof(*ev)); 355 break; 356 case MGMT_OP_READ_INDEX_LIST: 357 read_index_list_complete(sk, ev->data, len - sizeof(*ev)); 358 break; 359 case MGMT_OP_READ_INFO: 360 read_info_complete(sk, ev->data, len - sizeof(*ev)); 361 break; 362 default: 363 error("Unknown command complete for opcode %u", opcode); 364 break; 365 } 366} 367 368static void mgmt_cmd_status(int sk, void *buf, size_t len) 369{ 370 struct mgmt_ev_cmd_status *ev = buf; 371 uint16_t opcode; 372 373 if (len < sizeof(*ev)) { 374 error("Too small management command status event packet"); 375 return; 376 } 377 378 opcode = btohs(bt_get_unaligned(&ev->opcode)); 379 380 DBG("status %u opcode %u", ev->status, opcode); 381} 382 383static void mgmt_controller_error(int sk, void *buf, size_t len) 384{ 385 struct mgmt_ev_controller_error *ev = buf; 386 uint16_t index; 387 388 if (len < sizeof(*ev)) { 389 error("Too small management controller error event packet"); 390 return; 391 } 392 393 index = btohs(bt_get_unaligned(&ev->index)); 394 395 DBG("index %u error_code %u", index, ev->error_code); 396} 397 398static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data) 399{ 400 char buf[MGMT_BUF_SIZE]; 401 struct mgmt_hdr *hdr = (void *) buf; 402 int sk; 403 ssize_t ret; 404 uint16_t len, opcode; 405 406 DBG("cond %d", cond); 407 408 if (cond & G_IO_NVAL) 409 return FALSE; 410 411 sk = g_io_channel_unix_get_fd(io); 412 413 if (cond & (G_IO_ERR | G_IO_HUP)) { 414 error("Error on management socket"); 415 return FALSE; 416 } 417 418 ret = read(sk, buf, sizeof(buf)); 419 if (ret < 0) { 420 error("Unable to read from management socket: %s (%d)", 421 strerror(errno), errno); 422 return TRUE; 423 } 424 425 DBG("Received %zd bytes from management socket", ret); 426 427 if (ret < MGMT_HDR_SIZE) { 428 error("Too small Management packet"); 429 return TRUE; 430 } 431 432 opcode = btohs(bt_get_unaligned(&hdr->opcode)); 433 len = btohs(bt_get_unaligned(&hdr->len)); 434 435 if (ret != MGMT_HDR_SIZE + len) { 436 error("Packet length mismatch. ret %zd len %u", ret, len); 437 return TRUE; 438 } 439 440 switch (opcode) { 441 case MGMT_EV_CMD_COMPLETE: 442 mgmt_cmd_complete(sk, buf + MGMT_HDR_SIZE, len); 443 break; 444 case MGMT_EV_CMD_STATUS: 445 mgmt_cmd_status(sk, buf + MGMT_HDR_SIZE, len); 446 break; 447 case MGMT_EV_CONTROLLER_ERROR: 448 mgmt_controller_error(sk, buf + MGMT_HDR_SIZE, len); 449 break; 450 case MGMT_EV_INDEX_ADDED: 451 mgmt_index_added(sk, buf + MGMT_HDR_SIZE, len); 452 break; 453 case MGMT_EV_INDEX_REMOVED: 454 mgmt_index_removed(sk, buf + MGMT_HDR_SIZE, len); 455 break; 456 case MGMT_EV_POWERED: 457 mgmt_powered(sk, buf + MGMT_HDR_SIZE, len); 458 break; 459 default: 460 error("Unknown Management opcode %u", opcode); 461 break; 462 } 463 464 return TRUE; 465} 466 467static int mgmt_setup(void) 468{ 469 struct mgmt_hdr hdr; 470 struct sockaddr_hci addr; 471 GIOChannel *io; 472 GIOCondition condition; 473 int dd, err; 474 475 dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 476 if (dd < 0) 477 return -errno; 478 479 memset(&addr, 0, sizeof(addr)); 480 addr.hci_family = AF_BLUETOOTH; 481 addr.hci_dev = HCI_DEV_NONE; 482 addr.hci_channel = HCI_CHANNEL_CONTROL; 483 484 if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 485 err = -errno; 486 goto fail; 487 } 488 489 memset(&hdr, 0, sizeof(hdr)); 490 hdr.opcode = MGMT_OP_READ_VERSION; 491 if (write(dd, &hdr, sizeof(hdr)) < 0) { 492 err = -errno; 493 goto fail; 494 } 495 496 io = g_io_channel_unix_new(dd); 497 condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL; 498 mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL); 499 g_io_channel_unref(io); 500 501 mgmt_sock = dd; 502 503 info("Bluetooth Management interface initialized"); 504 505 return 0; 506 507fail: 508 close(dd); 509 return err; 510} 511 512static void mgmt_cleanup(void) 513{ 514 g_free(controllers); 515 controllers = NULL; 516 max_index = -1; 517 518 if (mgmt_sock >= 0) { 519 close(mgmt_sock); 520 mgmt_sock = -1; 521 } 522 523 if (mgmt_watch > 0) { 524 g_source_remove(mgmt_watch); 525 mgmt_watch = 0; 526 } 527} 528 529static int mgmt_power_on(int index, gboolean discoverable) 530{ 531 struct controller_info *info = &controllers[index]; 532 char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_power_on)]; 533 struct mgmt_hdr *hdr = (void *) buf; 534 struct mgmt_cp_power_on *cp = (void *) &buf[sizeof(*hdr)]; 535 536 DBG("index %d discoverable %d", index, discoverable); 537 538 memset(buf, 0, sizeof(buf)); 539 hdr->opcode = MGMT_OP_POWER_ON; 540 hdr->len = htobs(sizeof(*cp)); 541 542 cp->index = htobs(index); 543 cp->discoverable = discoverable; 544 cp->pairable = info->pairable; 545 546 if (write(mgmt_sock, buf, sizeof(buf)) < 0) 547 return -errno; 548 549 return 0; 550} 551 552static int mgmt_set_connectable(int index, gboolean connectable) 553{ 554 DBG("index %d connectable %d", index, connectable); 555 return -ENOSYS; 556} 557 558static int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor) 559{ 560 DBG("index %d major %u minor %u", index, major, minor); 561 return -ENOSYS; 562} 563 564static int mgmt_set_limited_discoverable(int index, gboolean limited) 565{ 566 DBG("index %d limited %d", index, limited); 567 return -ENOSYS; 568} 569 570static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic) 571{ 572 DBG("index %d length %u periodic %d", index, length, periodic); 573 return -ENOSYS; 574} 575 576static int mgmt_stop_inquiry(int index) 577{ 578 DBG("index %d", index); 579 return -ENOSYS; 580} 581 582static int mgmt_start_scanning(int index) 583{ 584 DBG("index %d", index); 585 return -ENOSYS; 586} 587 588static int mgmt_stop_scanning(int index) 589{ 590 DBG("index %d", index); 591 return -ENOSYS; 592} 593 594static int mgmt_resolve_name(int index, bdaddr_t *bdaddr) 595{ 596 char addr[18]; 597 598 ba2str(bdaddr, addr); 599 DBG("index %d addr %s", index, addr); 600 601 return -ENOSYS; 602} 603 604static int mgmt_set_name(int index, const char *name) 605{ 606 DBG("index %d, name %s", index, name); 607 return -ENOSYS; 608} 609 610static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr) 611{ 612 char addr[18]; 613 614 ba2str(bdaddr, addr); 615 DBG("index %d addr %s", index, addr); 616 617 return -ENOSYS; 618} 619 620static int mgmt_fast_connectable(int index, gboolean enable) 621{ 622 DBG("index %d enable %d", index, enable); 623 return -ENOSYS; 624} 625 626static int mgmt_read_clock(int index, bdaddr_t *bdaddr, int which, int timeout, 627 uint32_t *clock, uint16_t *accuracy) 628{ 629 char addr[18]; 630 631 ba2str(bdaddr, addr); 632 DBG("index %d addr %s which %d timeout %d", index, addr, which, 633 timeout); 634 635 return -ENOSYS; 636} 637 638static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr) 639{ 640 char addr[18]; 641 struct controller_info *info = &controllers[index]; 642 643 ba2str(&info->bdaddr, addr); 644 DBG("index %d addr %s", index, addr); 645 646 if (!info->valid) 647 return -ENODEV; 648 649 bacpy(bdaddr, &info->bdaddr); 650 651 return 0; 652} 653 654static int mgmt_block_device(int index, bdaddr_t *bdaddr) 655{ 656 char addr[18]; 657 658 ba2str(bdaddr, addr); 659 DBG("index %d addr %s", index, addr); 660 661 return -ENOSYS; 662} 663 664static int mgmt_unblock_device(int index, bdaddr_t *bdaddr) 665{ 666 char addr[18]; 667 668 ba2str(bdaddr, addr); 669 DBG("index %d addr %s", index, addr); 670 671 return -ENOSYS; 672} 673 674static int mgmt_get_conn_list(int index, GSList **conns) 675{ 676 DBG("index %d", index); 677 return -ENOSYS; 678} 679 680static int mgmt_read_local_version(int index, struct hci_version *ver) 681{ 682 struct controller_info *info = &controllers[index]; 683 684 DBG("index %d", index); 685 686 if (!info->valid) 687 return -ENODEV; 688 689 memset(ver, 0, sizeof(*ver)); 690 ver->manufacturer = info->manufacturer; 691 ver->hci_ver = info->hci_ver; 692 ver->hci_rev = info->hci_rev; 693 694 return 0; 695} 696 697static int mgmt_read_local_features(int index, uint8_t *features) 698{ 699 struct controller_info *info = &controllers[index]; 700 701 DBG("index %d", index); 702 703 if (!info->valid) 704 return -ENODEV; 705 706 memcpy(features, info->features, 8); 707 708 return 0; 709} 710 711static int mgmt_disconnect(int index, uint16_t handle) 712{ 713 DBG("index %d handle %u", index, handle); 714 return -ENOSYS; 715} 716 717static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr) 718{ 719 char addr[18]; 720 721 ba2str(bdaddr, addr); 722 DBG("index %d addr %s", index, addr); 723 724 return -ENOSYS; 725} 726 727static int mgmt_request_authentication(int index, uint16_t handle) 728{ 729 DBG("index %d handle %u", index, handle); 730 return -ENOSYS; 731} 732 733static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin) 734{ 735 char addr[18]; 736 737 ba2str(bdaddr, addr); 738 DBG("index %d addr %s pin %s", index, addr, pin); 739 740 return -ENOSYS; 741} 742 743static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success) 744{ 745 char addr[18]; 746 747 ba2str(bdaddr, addr); 748 DBG("index %d addr %s success %d", index, addr, success); 749 750 return -ENOSYS; 751} 752 753static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey) 754{ 755 char addr[18]; 756 757 ba2str(bdaddr, addr); 758 DBG("index %d addr %s passkey %06u", index, addr, passkey); 759 760 return -ENOSYS; 761} 762 763static int mgmt_get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth) 764{ 765 char addr[18]; 766 767 ba2str(bdaddr, addr); 768 DBG("index %d addr %s", index, addr); 769 770 return -ENOSYS; 771} 772 773static int mgmt_read_scan_enable(int index) 774{ 775 DBG("index %d", index); 776 return -ENOSYS; 777} 778 779static int mgmt_enable_le(int index) 780{ 781 DBG("index %d", index); 782 return -ENOSYS; 783} 784 785static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb, 786 gpointer user_data) 787{ 788 char addr[18]; 789 790 ba2str(dst, addr); 791 DBG("index %d addr %s", index, addr); 792 793 return -ENOSYS; 794} 795 796static int mgmt_set_did(int index, uint16_t vendor, uint16_t product, 797 uint16_t version) 798{ 799 DBG("index %d vendor %u product %u version %u", 800 index, vendor, product, version); 801 return -ENOSYS; 802} 803 804static int mgmt_services_updated(int index) 805{ 806 DBG("index %d", index); 807 return -ENOSYS; 808} 809 810static int mgmt_disable_cod_cache(int index) 811{ 812 DBG("index %d", index); 813 return -ENOSYS; 814} 815 816static int mgmt_restore_powered(int index) 817{ 818 DBG("index %d", index); 819 return -ENOSYS; 820} 821 822static int mgmt_load_keys(int index, GSList *keys) 823{ 824 DBG("index %d keys %d", index, g_slist_length(keys)); 825 return -ENOSYS; 826} 827 828static struct btd_adapter_ops mgmt_ops = { 829 .setup = mgmt_setup, 830 .cleanup = mgmt_cleanup, 831 .power_on = mgmt_power_on, 832 .power_off = mgmt_power_off, 833 .set_connectable = mgmt_set_connectable, 834 .set_discoverable = mgmt_set_discoverable, 835 .set_pairable = mgmt_set_pairable, 836 .set_limited_discoverable = mgmt_set_limited_discoverable, 837 .start_inquiry = mgmt_start_inquiry, 838 .stop_inquiry = mgmt_stop_inquiry, 839 .start_scanning = mgmt_start_scanning, 840 .stop_scanning = mgmt_stop_scanning, 841 .resolve_name = mgmt_resolve_name, 842 .cancel_resolve_name = mgmt_cancel_resolve_name, 843 .set_name = mgmt_set_name, 844 .set_dev_class = mgmt_set_dev_class, 845 .set_fast_connectable = mgmt_fast_connectable, 846 .read_clock = mgmt_read_clock, 847 .read_bdaddr = mgmt_read_bdaddr, 848 .block_device = mgmt_block_device, 849 .unblock_device = mgmt_unblock_device, 850 .get_conn_list = mgmt_get_conn_list, 851 .read_local_version = mgmt_read_local_version, 852 .read_local_features = mgmt_read_local_features, 853 .disconnect = mgmt_disconnect, 854 .remove_bonding = mgmt_remove_bonding, 855 .request_authentication = mgmt_request_authentication, 856 .pincode_reply = mgmt_pincode_reply, 857 .confirm_reply = mgmt_confirm_reply, 858 .passkey_reply = mgmt_passkey_reply, 859 .get_auth_info = mgmt_get_auth_info, 860 .read_scan_enable = mgmt_read_scan_enable, 861 .enable_le = mgmt_enable_le, 862 .encrypt_link = mgmt_encrypt_link, 863 .set_did = mgmt_set_did, 864 .services_updated = mgmt_services_updated, 865 .disable_cod_cache = mgmt_disable_cod_cache, 866 .restore_powered = mgmt_restore_powered, 867 .load_keys = mgmt_load_keys, 868}; 869 870static int mgmt_init(void) 871{ 872 return btd_register_adapter_ops(&mgmt_ops, TRUE); 873} 874 875static void mgmt_exit(void) 876{ 877 btd_adapter_cleanup_ops(&mgmt_ops); 878} 879 880BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION, 881 BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit) 882