mgmtops.c revision 6a63c312559ef5d83c32db9ea57435786cdebada
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_set_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_dev_class(int index, uint8_t major, uint8_t minor) 468{ 469 DBG("index %d major %u minor %u", index, major, minor); 470 return -ENOSYS; 471} 472 473static int mgmt_set_limited_discoverable(int index, gboolean limited) 474{ 475 DBG("index %d limited %d", index, limited); 476 return -ENOSYS; 477} 478 479static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic) 480{ 481 DBG("index %d length %u periodic %d", index, length, periodic); 482 return -ENOSYS; 483} 484 485static int mgmt_stop_inquiry(int index) 486{ 487 DBG("index %d", index); 488 return -ENOSYS; 489} 490 491static int mgmt_start_scanning(int index) 492{ 493 DBG("index %d", index); 494 return -ENOSYS; 495} 496 497static int mgmt_stop_scanning(int index) 498{ 499 DBG("index %d", index); 500 return -ENOSYS; 501} 502 503static int mgmt_resolve_name(int index, bdaddr_t *bdaddr) 504{ 505 char addr[18]; 506 507 ba2str(bdaddr, addr); 508 DBG("index %d addr %s", index, addr); 509 510 return -ENOSYS; 511} 512 513static int mgmt_set_name(int index, const char *name) 514{ 515 DBG("index %d, name %s", index, name); 516 return -ENOSYS; 517} 518 519static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr) 520{ 521 char addr[18]; 522 523 ba2str(bdaddr, addr); 524 DBG("index %d addr %s", index, addr); 525 526 return -ENOSYS; 527} 528 529static int mgmt_fast_connectable(int index, gboolean enable) 530{ 531 DBG("index %d enable %d", index, enable); 532 return -ENOSYS; 533} 534 535static int mgmt_read_clock(int index, int handle, int which, int timeout, 536 uint32_t *clock, uint16_t *accuracy) 537{ 538 DBG("index %d handle %d which %d timeout %d", index, handle, 539 which, timeout); 540 return -ENOSYS; 541} 542 543static int mgmt_conn_handle(int index, const bdaddr_t *bdaddr, int *handle) 544{ 545 char addr[18]; 546 547 ba2str(bdaddr, addr); 548 DBG("index %d addr %s", index, addr); 549 550 return -ENOSYS; 551} 552 553static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr) 554{ 555 char addr[18]; 556 struct controller_info *info = &controllers[index]; 557 558 ba2str(&info->bdaddr, addr); 559 DBG("index %d addr %s", index, addr); 560 561 if (!info->valid) 562 return -ENODEV; 563 564 bacpy(bdaddr, &info->bdaddr); 565 566 return 0; 567} 568 569static int mgmt_block_device(int index, bdaddr_t *bdaddr) 570{ 571 char addr[18]; 572 573 ba2str(bdaddr, addr); 574 DBG("index %d addr %s", index, addr); 575 576 return -ENOSYS; 577} 578 579static int mgmt_unblock_device(int index, bdaddr_t *bdaddr) 580{ 581 char addr[18]; 582 583 ba2str(bdaddr, addr); 584 DBG("index %d addr %s", index, addr); 585 586 return -ENOSYS; 587} 588 589static int mgmt_get_conn_list(int index, GSList **conns) 590{ 591 DBG("index %d", index); 592 return -ENOSYS; 593} 594 595static int mgmt_read_local_version(int index, struct hci_version *ver) 596{ 597 struct controller_info *info = &controllers[index]; 598 599 DBG("index %d", index); 600 601 if (!info->valid) 602 return -ENODEV; 603 604 memset(ver, 0, sizeof(*ver)); 605 ver->manufacturer = info->manufacturer; 606 ver->hci_ver = info->hci_ver; 607 ver->hci_rev = info->hci_rev; 608 609 return 0; 610} 611 612static int mgmt_read_local_features(int index, uint8_t *features) 613{ 614 struct controller_info *info = &controllers[index]; 615 616 DBG("index %d", index); 617 618 if (!info->valid) 619 return -ENODEV; 620 621 memcpy(features, info->features, 8); 622 623 return 0; 624} 625 626static int mgmt_read_local_ext_features(int index) 627{ 628 DBG("index %d", index); 629 return -ENOSYS; 630} 631 632static int mgmt_disconnect(int index, uint16_t handle) 633{ 634 DBG("index %d handle %u", index, handle); 635 return -ENOSYS; 636} 637 638static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr) 639{ 640 char addr[18]; 641 642 ba2str(bdaddr, addr); 643 DBG("index %d addr %s", index, addr); 644 645 return -ENOSYS; 646} 647 648static int mgmt_request_authentication(int index, uint16_t handle) 649{ 650 DBG("index %d handle %u", index, handle); 651 return -ENOSYS; 652} 653 654static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin) 655{ 656 char addr[18]; 657 658 ba2str(bdaddr, addr); 659 DBG("index %d addr %s pin %s", index, addr, pin); 660 661 return -ENOSYS; 662} 663 664static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success) 665{ 666 char addr[18]; 667 668 ba2str(bdaddr, addr); 669 DBG("index %d addr %s success %d", index, addr, success); 670 671 return -ENOSYS; 672} 673 674static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey) 675{ 676 char addr[18]; 677 678 ba2str(bdaddr, addr); 679 DBG("index %d addr %s passkey %06u", index, addr, passkey); 680 681 return -ENOSYS; 682} 683 684static int mgmt_get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth) 685{ 686 char addr[18]; 687 688 ba2str(bdaddr, addr); 689 DBG("index %d addr %s", index, addr); 690 691 return -ENOSYS; 692} 693 694static int mgmt_read_scan_enable(int index) 695{ 696 DBG("index %d", index); 697 return -ENOSYS; 698} 699 700static int mgmt_write_le_host(int index, uint8_t le, uint8_t simul) 701{ 702 DBG("index %d le %u simul %u", index, le, simul); 703 return -ENOSYS; 704} 705 706static int mgmt_get_remote_version(int index, uint16_t handle, 707 gboolean delayed) 708{ 709 DBG("index %d handle %u delayed %d", index, handle, delayed); 710 return -ENOSYS; 711} 712 713static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb, 714 gpointer user_data) 715{ 716 char addr[18]; 717 718 ba2str(dst, addr); 719 DBG("index %d addr %s", index, addr); 720 721 return -ENOSYS; 722} 723 724static struct btd_adapter_ops mgmt_ops = { 725 .setup = mgmt_setup, 726 .cleanup = mgmt_cleanup, 727 .start = mgmt_start, 728 .stop = mgmt_stop, 729 .set_powered = mgmt_set_powered, 730 .set_connectable = mgmt_connectable, 731 .set_discoverable = mgmt_discoverable, 732 .set_limited_discoverable = mgmt_set_limited_discoverable, 733 .start_inquiry = mgmt_start_inquiry, 734 .stop_inquiry = mgmt_stop_inquiry, 735 .start_scanning = mgmt_start_scanning, 736 .stop_scanning = mgmt_stop_scanning, 737 .resolve_name = mgmt_resolve_name, 738 .cancel_resolve_name = mgmt_cancel_resolve_name, 739 .set_name = mgmt_set_name, 740 .set_dev_class = mgmt_set_dev_class, 741 .set_fast_connectable = mgmt_fast_connectable, 742 .read_clock = mgmt_read_clock, 743 .get_conn_handle = mgmt_conn_handle, 744 .read_bdaddr = mgmt_read_bdaddr, 745 .block_device = mgmt_block_device, 746 .unblock_device = mgmt_unblock_device, 747 .get_conn_list = mgmt_get_conn_list, 748 .read_local_version = mgmt_read_local_version, 749 .read_local_features = mgmt_read_local_features, 750 .read_local_ext_features = mgmt_read_local_ext_features, 751 .disconnect = mgmt_disconnect, 752 .remove_bonding = mgmt_remove_bonding, 753 .request_authentication = mgmt_request_authentication, 754 .pincode_reply = mgmt_pincode_reply, 755 .confirm_reply = mgmt_confirm_reply, 756 .passkey_reply = mgmt_passkey_reply, 757 .get_auth_info = mgmt_get_auth_info, 758 .read_scan_enable = mgmt_read_scan_enable, 759 .write_le_host = mgmt_write_le_host, 760 .get_remote_version = mgmt_get_remote_version, 761 .encrypt_link = mgmt_encrypt_link, 762}; 763 764static int mgmt_init(void) 765{ 766 return btd_register_adapter_ops(&mgmt_ops, TRUE); 767} 768 769static void mgmt_exit(void) 770{ 771 btd_adapter_cleanup_ops(&mgmt_ops); 772} 773 774BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION, 775 BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit) 776