mgmtops.c revision 983bc0f8ccd66ec217421288a0b5fb2c38b604bd
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 "manager.h" 45#include "adapter.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 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 read_index_list_complete(int sk, void *buf, size_t len) 175{ 176 struct mgmt_rp_read_index_list *rp = buf; 177 uint16_t num; 178 int i; 179 180 if (len < sizeof(*rp)) { 181 error("Too small read index list complete event"); 182 return; 183 } 184 185 num = btohs(bt_get_unaligned(&rp->num_controllers)); 186 187 if (num * sizeof(uint16_t) + sizeof(*rp) != len) { 188 error("Incorrect packet size for index list event"); 189 return; 190 } 191 192 for (i = 0; i < num; i++) { 193 uint16_t index; 194 195 index = btohs(bt_get_unaligned(&rp->index[i])); 196 197 add_controller(index); 198 read_info(sk, index); 199 } 200} 201 202static void read_info_complete(int sk, void *buf, size_t len) 203{ 204 struct mgmt_rp_read_info *rp = buf; 205 struct controller_info *info; 206 uint16_t index; 207 char addr[18]; 208 209 if (len < sizeof(*rp)) { 210 error("Too small read info complete event"); 211 return; 212 } 213 214 index = btohs(bt_get_unaligned(&rp->index)); 215 if (index > max_index) { 216 error("Unexpected index %u in read info complete", index); 217 return; 218 } 219 220 info = &controllers[index]; 221 info->type = rp->type; 222 info->enabled = rp->powered; 223 info->discoverable = rp->discoverable; 224 info->pairable = rp->pairable; 225 info->sec_mode = rp->sec_mode; 226 bacpy(&info->bdaddr, &rp->bdaddr); 227 memcpy(info->dev_class, rp->dev_class, 3); 228 memcpy(info->features, rp->features, 8); 229 info->manufacturer = btohs(bt_get_unaligned(&rp->manufacturer)); 230 info->hci_ver = rp->hci_ver; 231 info->hci_rev = btohs(bt_get_unaligned(&rp->hci_rev)); 232 233 ba2str(&info->bdaddr, addr); 234 DBG("hci%u type %u addr %s", index, info->type, addr); 235 DBG("hci%u class 0x%02x%02x%02x", index, 236 info->dev_class[2], info->dev_class[1], info->dev_class[0]); 237 DBG("hci%u manufacturer %d HCI ver %d:%d", index, info->manufacturer, 238 info->hci_ver, info->hci_rev); 239 DBG("hci%u enabled %u discoverable %u pairable %u sec_mode %u", index, 240 info->enabled, info->discoverable, 241 info->pairable, info->sec_mode); 242 243 manager_register_adapter(index, info->enabled); 244 245 if (info->enabled) 246 manager_start_adapter(index); 247} 248 249static void mgmt_cmd_complete(int sk, void *buf, size_t len) 250{ 251 struct mgmt_ev_cmd_complete *ev = buf; 252 uint16_t opcode; 253 254 DBG(""); 255 256 if (len < sizeof(*ev)) { 257 error("Too small management command complete event packet"); 258 return; 259 } 260 261 opcode = btohs(bt_get_unaligned(&ev->opcode)); 262 263 switch (opcode) { 264 case MGMT_OP_READ_VERSION: 265 read_version_complete(sk, ev->data, len - sizeof(*ev)); 266 break; 267 case MGMT_OP_READ_INDEX_LIST: 268 read_index_list_complete(sk, ev->data, len - sizeof(*ev)); 269 break; 270 case MGMT_OP_READ_INFO: 271 read_info_complete(sk, ev->data, len - sizeof(*ev)); 272 break; 273 default: 274 error("Unknown command complete for opcode %u", opcode); 275 break; 276 } 277} 278 279static void mgmt_cmd_status(int sk, void *buf, size_t len) 280{ 281 struct mgmt_ev_cmd_status *ev = buf; 282 uint16_t opcode; 283 284 if (len < sizeof(*ev)) { 285 error("Too small management command status event packet"); 286 return; 287 } 288 289 opcode = btohs(bt_get_unaligned(&ev->opcode)); 290 291 DBG("status %u opcode %u", ev->status, opcode); 292} 293 294static void mgmt_controller_error(int sk, void *buf, size_t len) 295{ 296 struct mgmt_ev_controller_error *ev = buf; 297 uint16_t index; 298 299 if (len < sizeof(*ev)) { 300 error("Too small management controller error event packet"); 301 return; 302 } 303 304 index = btohs(bt_get_unaligned(&ev->index)); 305 306 DBG("index %u error_code %u", index, ev->error_code); 307} 308 309static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data) 310{ 311 char buf[MGMT_BUF_SIZE]; 312 struct mgmt_hdr *hdr = (void *) buf; 313 int sk; 314 ssize_t ret; 315 uint16_t len, opcode; 316 317 DBG("cond %d", cond); 318 319 if (cond & G_IO_NVAL) 320 return FALSE; 321 322 sk = g_io_channel_unix_get_fd(io); 323 324 if (cond & (G_IO_ERR | G_IO_HUP)) { 325 error("Error on management socket"); 326 return FALSE; 327 } 328 329 ret = read(sk, buf, sizeof(buf)); 330 if (ret < 0) { 331 error("Unable to read from management socket: %s (%d)", 332 strerror(errno), errno); 333 return TRUE; 334 } 335 336 DBG("Received %zd bytes from management socket", ret); 337 338 if (ret < MGMT_HDR_SIZE) { 339 error("Too small Management packet"); 340 return TRUE; 341 } 342 343 opcode = btohs(bt_get_unaligned(&hdr->opcode)); 344 len = btohs(bt_get_unaligned(&hdr->len)); 345 346 if (ret != MGMT_HDR_SIZE + len) { 347 error("Packet length mismatch. ret %zd len %u", ret, len); 348 return TRUE; 349 } 350 351 switch (opcode) { 352 case MGMT_EV_CMD_COMPLETE: 353 mgmt_cmd_complete(sk, buf + MGMT_HDR_SIZE, len); 354 break; 355 case MGMT_EV_CMD_STATUS: 356 mgmt_cmd_status(sk, buf + MGMT_HDR_SIZE, len); 357 break; 358 case MGMT_EV_CONTROLLER_ERROR: 359 mgmt_controller_error(sk, buf + MGMT_HDR_SIZE, len); 360 break; 361 case MGMT_EV_INDEX_ADDED: 362 mgmt_index_added(sk, buf + MGMT_HDR_SIZE, len); 363 break; 364 case MGMT_EV_INDEX_REMOVED: 365 mgmt_index_removed(sk, buf + MGMT_HDR_SIZE, len); 366 break; 367 default: 368 error("Unknown Management opcode %u", opcode); 369 break; 370 } 371 372 return TRUE; 373} 374 375static int mgmt_setup(void) 376{ 377 struct mgmt_hdr hdr; 378 struct sockaddr_hci addr; 379 GIOChannel *io; 380 GIOCondition condition; 381 int dd, err; 382 383 dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 384 if (dd < 0) 385 return -errno; 386 387 memset(&addr, 0, sizeof(addr)); 388 addr.hci_family = AF_BLUETOOTH; 389 addr.hci_dev = HCI_DEV_NONE; 390 addr.hci_channel = HCI_CHANNEL_CONTROL; 391 392 if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 393 err = -errno; 394 goto fail; 395 } 396 397 memset(&hdr, 0, sizeof(hdr)); 398 hdr.opcode = MGMT_OP_READ_VERSION; 399 if (write(dd, &hdr, sizeof(hdr)) < 0) { 400 err = -errno; 401 goto fail; 402 } 403 404 io = g_io_channel_unix_new(dd); 405 condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL; 406 mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL); 407 g_io_channel_unref(io); 408 409 mgmt_sock = dd; 410 411 info("Bluetooth Management interface initialized"); 412 413 return 0; 414 415fail: 416 close(dd); 417 return err; 418} 419 420static void mgmt_cleanup(void) 421{ 422 g_free(controllers); 423 controllers = NULL; 424 max_index = -1; 425 426 if (mgmt_sock >= 0) { 427 close(mgmt_sock); 428 mgmt_sock = -1; 429 } 430 431 if (mgmt_watch > 0) { 432 g_source_remove(mgmt_watch); 433 mgmt_watch = 0; 434 } 435} 436 437static int mgmt_start(int index) 438{ 439 DBG("index %d", index); 440 return -ENOSYS; 441} 442 443static int mgmt_stop(int index) 444{ 445 DBG("index %d", index); 446 return -ENOSYS; 447} 448 449static int mgmt_powered(int index, gboolean powered) 450{ 451 DBG("index %d powered %d", index, powered); 452 return -ENOSYS; 453} 454 455static int mgmt_connectable(int index) 456{ 457 DBG("index %d", index); 458 return -ENOSYS; 459} 460 461static int mgmt_discoverable(int index) 462{ 463 DBG("index %d", index); 464 return -ENOSYS; 465} 466 467static int mgmt_set_class(int index, uint32_t class) 468{ 469 DBG("index %d class %u", index, class); 470 return -ENOSYS; 471} 472 473static int mgmt_set_limited_discoverable(int index, uint32_t class, 474 gboolean limited) 475{ 476 DBG("index %d class %u, limited %d", index, class, limited); 477 return -ENOSYS; 478} 479 480static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic) 481{ 482 DBG("index %d length %u periodic %d", index, length, periodic); 483 return -ENOSYS; 484} 485 486static int mgmt_stop_inquiry(int index) 487{ 488 DBG("index %d", index); 489 return -ENOSYS; 490} 491 492static int mgmt_start_scanning(int index) 493{ 494 DBG("index %d", index); 495 return -ENOSYS; 496} 497 498static int mgmt_stop_scanning(int index) 499{ 500 DBG("index %d", index); 501 return -ENOSYS; 502} 503 504static int mgmt_resolve_name(int index, bdaddr_t *bdaddr) 505{ 506 char addr[18]; 507 508 ba2str(bdaddr, addr); 509 DBG("index %d addr %s", index, addr); 510 511 return -ENOSYS; 512} 513 514static int mgmt_set_name(int index, const char *name) 515{ 516 DBG("index %d, name %s", index, name); 517 return -ENOSYS; 518} 519 520static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr) 521{ 522 char addr[18]; 523 524 ba2str(bdaddr, addr); 525 DBG("index %d addr %s", index, addr); 526 527 return -ENOSYS; 528} 529 530static int mgmt_fast_connectable(int index, gboolean enable) 531{ 532 DBG("index %d enable %d", index, enable); 533 return -ENOSYS; 534} 535 536static int mgmt_read_clock(int index, int handle, int which, int timeout, 537 uint32_t *clock, uint16_t *accuracy) 538{ 539 DBG("index %d handle %d which %d timeout %d", index, handle, 540 which, timeout); 541 return -ENOSYS; 542} 543 544static int mgmt_conn_handle(int index, const bdaddr_t *bdaddr, int *handle) 545{ 546 char addr[18]; 547 548 ba2str(bdaddr, addr); 549 DBG("index %d addr %s", index, addr); 550 551 return -ENOSYS; 552} 553 554static int mgmt_write_eir_data(int index, uint8_t *data) 555{ 556 DBG("index %d", index); 557 return -ENOSYS; 558} 559 560static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr) 561{ 562 char addr[18]; 563 struct controller_info *info = &controllers[index]; 564 565 ba2str(&info->bdaddr, addr); 566 DBG("index %d addr %s", index, addr); 567 568 if (!info->valid) 569 return -ENODEV; 570 571 bacpy(bdaddr, &info->bdaddr); 572 573 return 0; 574} 575 576static int mgmt_block_device(int index, bdaddr_t *bdaddr) 577{ 578 char addr[18]; 579 580 ba2str(bdaddr, addr); 581 DBG("index %d addr %s", index, addr); 582 583 return -ENOSYS; 584} 585 586static int mgmt_unblock_device(int index, bdaddr_t *bdaddr) 587{ 588 char addr[18]; 589 590 ba2str(bdaddr, addr); 591 DBG("index %d addr %s", index, addr); 592 593 return -ENOSYS; 594} 595 596static int mgmt_get_conn_list(int index, GSList **conns) 597{ 598 DBG("index %d", index); 599 return -ENOSYS; 600} 601 602static int mgmt_read_local_version(int index, struct hci_version *ver) 603{ 604 struct controller_info *info = &controllers[index]; 605 606 DBG("index %d", index); 607 608 if (!info->valid) 609 return -ENODEV; 610 611 memset(ver, 0, sizeof(*ver)); 612 ver->manufacturer = info->manufacturer; 613 ver->hci_ver = info->hci_ver; 614 ver->hci_rev = info->hci_rev; 615 616 return 0; 617} 618 619static int mgmt_read_local_features(int index, uint8_t *features) 620{ 621 struct controller_info *info = &controllers[index]; 622 623 DBG("index %d", index); 624 625 if (!info->valid) 626 return -ENODEV; 627 628 memcpy(features, info->features, 8); 629 630 return 0; 631} 632 633static int mgmt_read_local_ext_features(int index) 634{ 635 DBG("index %d", index); 636 return -ENOSYS; 637} 638 639static int mgmt_disconnect(int index, uint16_t handle) 640{ 641 DBG("index %d handle %u", index, handle); 642 return -ENOSYS; 643} 644 645static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr) 646{ 647 char addr[18]; 648 649 ba2str(bdaddr, addr); 650 DBG("index %d addr %s", index, addr); 651 652 return -ENOSYS; 653} 654 655static int mgmt_request_authentication(int index, uint16_t handle) 656{ 657 DBG("index %d handle %u", index, handle); 658 return -ENOSYS; 659} 660 661static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin) 662{ 663 char addr[18]; 664 665 ba2str(bdaddr, addr); 666 DBG("index %d addr %s pin %s", index, addr, pin); 667 668 return -ENOSYS; 669} 670 671static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success) 672{ 673 char addr[18]; 674 675 ba2str(bdaddr, addr); 676 DBG("index %d addr %s success %d", index, addr, success); 677 678 return -ENOSYS; 679} 680 681static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey) 682{ 683 char addr[18]; 684 685 ba2str(bdaddr, addr); 686 DBG("index %d addr %s passkey %06u", index, addr, passkey); 687 688 return -ENOSYS; 689} 690 691static int mgmt_get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth) 692{ 693 char addr[18]; 694 695 ba2str(bdaddr, addr); 696 DBG("index %d addr %s", index, addr); 697 698 return -ENOSYS; 699} 700 701static int mgmt_read_scan_enable(int index) 702{ 703 DBG("index %d", index); 704 return -ENOSYS; 705} 706 707static int mgmt_write_le_host(int index, uint8_t le, uint8_t simul) 708{ 709 DBG("index %d le %u simul %u", index, le, simul); 710 return -ENOSYS; 711} 712 713static int mgmt_get_remote_version(int index, uint16_t handle, 714 gboolean delayed) 715{ 716 DBG("index %d handle %u delayed %d", index, handle, delayed); 717 return -ENOSYS; 718} 719 720static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb, 721 gpointer user_data) 722{ 723 char addr[18]; 724 725 ba2str(dst, addr); 726 DBG("index %d addr %s", index, addr); 727 728 return -ENOSYS; 729} 730 731static struct btd_adapter_ops mgmt_ops = { 732 .setup = mgmt_setup, 733 .cleanup = mgmt_cleanup, 734 .start = mgmt_start, 735 .stop = mgmt_stop, 736 .set_powered = mgmt_powered, 737 .set_connectable = mgmt_connectable, 738 .set_discoverable = mgmt_discoverable, 739 .set_limited_discoverable = mgmt_set_limited_discoverable, 740 .start_inquiry = mgmt_start_inquiry, 741 .stop_inquiry = mgmt_stop_inquiry, 742 .start_scanning = mgmt_start_scanning, 743 .stop_scanning = mgmt_stop_scanning, 744 .resolve_name = mgmt_resolve_name, 745 .cancel_resolve_name = mgmt_cancel_resolve_name, 746 .set_name = mgmt_set_name, 747 .set_class = mgmt_set_class, 748 .set_fast_connectable = mgmt_fast_connectable, 749 .read_clock = mgmt_read_clock, 750 .get_conn_handle = mgmt_conn_handle, 751 .write_eir_data = mgmt_write_eir_data, 752 .read_bdaddr = mgmt_read_bdaddr, 753 .block_device = mgmt_block_device, 754 .unblock_device = mgmt_unblock_device, 755 .get_conn_list = mgmt_get_conn_list, 756 .read_local_version = mgmt_read_local_version, 757 .read_local_features = mgmt_read_local_features, 758 .read_local_ext_features = mgmt_read_local_ext_features, 759 .disconnect = mgmt_disconnect, 760 .remove_bonding = mgmt_remove_bonding, 761 .request_authentication = mgmt_request_authentication, 762 .pincode_reply = mgmt_pincode_reply, 763 .confirm_reply = mgmt_confirm_reply, 764 .passkey_reply = mgmt_passkey_reply, 765 .get_auth_info = mgmt_get_auth_info, 766 .read_scan_enable = mgmt_read_scan_enable, 767 .write_le_host = mgmt_write_le_host, 768 .get_remote_version = mgmt_get_remote_version, 769 .encrypt_link = mgmt_encrypt_link, 770}; 771 772static int mgmt_init(void) 773{ 774 return btd_register_adapter_ops(&mgmt_ops, TRUE); 775} 776 777static void mgmt_exit(void) 778{ 779 btd_adapter_cleanup_ops(&mgmt_ops); 780} 781 782BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION, 783 BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit) 784