mgmtops.c revision 1d555f47c40b26e52b705f3985e63a900e268757
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 mgmt_sock = -1; 52static guint mgmt_watch = 0; 53 54static void read_version_complete(int sk, void *buf, size_t len) 55{ 56 struct hci_mgmt_read_version_rp *rp = buf; 57 uint16_t revision; 58 59 if (len < HCI_MGMT_READ_VERSION_RP_SIZE) { 60 error("Too small read version complete event"); 61 return; 62 } 63 64 revision = btohs(bt_get_unaligned(&rp->revision)); 65 66 DBG("status %u version %u revision %u", rp->status, rp->version, 67 revision); 68} 69 70static void mgmt_cmd_complete(int sk, void *buf, size_t len) 71{ 72 struct hci_mgmt_cmd_complete_ev *ev = buf; 73 uint16_t opcode; 74 75 DBG(""); 76 77 if (len < sizeof(*ev)) { 78 error("Too small management command complete event packet"); 79 return; 80 } 81 82 opcode = btohs(bt_get_unaligned(&ev->opcode)); 83 84 switch (opcode) { 85 case HCI_MGMT_OP_READ_VERSION: 86 read_version_complete(sk, ev->data, len - sizeof(*ev)); 87 break; 88 default: 89 error("Unknown command complete for opcode %u", opcode); 90 break; 91 } 92} 93 94static void mgmt_cmd_status(int sk, void *buf, size_t len) 95{ 96 DBG(""); 97} 98 99static void mgmt_controller_error(int sk, void *buf, size_t len) 100{ 101 DBG(""); 102} 103 104static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data) 105{ 106 char buf[MGMT_BUF_SIZE]; 107 struct hci_mgmt_hdr *hdr = (void *) buf; 108 int sk; 109 ssize_t ret; 110 uint16_t len, opcode; 111 112 DBG("cond %d", cond); 113 114 if (cond & G_IO_NVAL) 115 return FALSE; 116 117 sk = g_io_channel_unix_get_fd(io); 118 119 if (cond & (G_IO_ERR | G_IO_HUP)) { 120 error("Error on management socket"); 121 return FALSE; 122 } 123 124 ret = read(sk, buf, sizeof(buf)); 125 if (ret < 0) { 126 error("Unable to read from management socket: %s (%d)", 127 strerror(errno), errno); 128 return TRUE; 129 } 130 131 DBG("Received %zd bytes from management socket", ret); 132 133 if (ret < HCI_MGMT_HDR_SIZE) { 134 error("Too small Management packet"); 135 return TRUE; 136 } 137 138 opcode = btohs(bt_get_unaligned(&hdr->opcode)); 139 len = btohs(bt_get_unaligned(&hdr->len)); 140 141 if (ret != HCI_MGMT_HDR_SIZE + len) { 142 error("Packet length mismatch. ret %zd len %u", ret, len); 143 return TRUE; 144 } 145 146 switch (opcode) { 147 case HCI_MGMT_EV_CMD_COMPLETE: 148 mgmt_cmd_complete(sk, buf + HCI_MGMT_HDR_SIZE, len); 149 break; 150 case HCI_MGMT_EV_CMD_STATUS: 151 mgmt_cmd_status(sk, buf + HCI_MGMT_HDR_SIZE, len); 152 break; 153 case HCI_MGMT_EV_CONTROLLER_ERROR: 154 mgmt_controller_error(sk, buf + HCI_MGMT_HDR_SIZE, len); 155 break; 156 default: 157 error("Unknown Management opcode %u", opcode); 158 break; 159 } 160 161 return TRUE; 162} 163 164static int mgmt_setup(void) 165{ 166 struct hci_mgmt_hdr hdr; 167 struct sockaddr_hci addr; 168 GIOChannel *io; 169 GIOCondition condition; 170 int dd, err; 171 172 dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 173 if (dd < 0) 174 return -errno; 175 176 memset(&addr, 0, sizeof(addr)); 177 addr.hci_family = AF_BLUETOOTH; 178 addr.hci_dev = HCI_DEV_NONE; 179 addr.hci_channel = HCI_CHANNEL_CONTROL; 180 181 if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 182 err = -errno; 183 goto fail; 184 } 185 186 memset(&hdr, 0, sizeof(hdr)); 187 hdr.opcode = HCI_MGMT_OP_READ_VERSION; 188 if (write(dd, &hdr, sizeof(hdr)) < 0) { 189 err = -errno; 190 goto fail; 191 } 192 193 io = g_io_channel_unix_new(dd); 194 condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL; 195 mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL); 196 g_io_channel_unref(io); 197 198 mgmt_sock = dd; 199 200 info("Bluetooth Management interface initialized"); 201 202 return 0; 203 204fail: 205 close(dd); 206 return err; 207} 208 209static void mgmt_cleanup(void) 210{ 211 if (mgmt_sock >= 0) { 212 close(mgmt_sock); 213 mgmt_sock = -1; 214 } 215 216 if (mgmt_watch > 0) { 217 g_source_remove(mgmt_watch); 218 mgmt_watch = 0; 219 } 220} 221 222static int mgmt_start(int index) 223{ 224 DBG("index %d", index); 225 return -ENOSYS; 226} 227 228static int mgmt_stop(int index) 229{ 230 DBG("index %d", index); 231 return -ENOSYS; 232} 233 234static int mgmt_powered(int index, gboolean powered) 235{ 236 DBG("index %d powered %d", index, powered); 237 return -ENOSYS; 238} 239 240static int mgmt_connectable(int index) 241{ 242 DBG("index %d", index); 243 return -ENOSYS; 244} 245 246static int mgmt_discoverable(int index) 247{ 248 DBG("index %d", index); 249 return -ENOSYS; 250} 251 252static int mgmt_set_class(int index, uint32_t class) 253{ 254 DBG("index %d class %u", index, class); 255 return -ENOSYS; 256} 257 258static int mgmt_set_limited_discoverable(int index, uint32_t class, 259 gboolean limited) 260{ 261 DBG("index %d class %u, limited %d", index, class, limited); 262 return -ENOSYS; 263} 264 265static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic) 266{ 267 DBG("index %d length %u periodic %d", index, length, periodic); 268 return -ENOSYS; 269} 270 271static int mgmt_stop_inquiry(int index) 272{ 273 DBG("index %d", index); 274 return -ENOSYS; 275} 276 277static int mgmt_start_scanning(int index) 278{ 279 DBG("index %d", index); 280 return -ENOSYS; 281} 282 283static int mgmt_stop_scanning(int index) 284{ 285 DBG("index %d", index); 286 return -ENOSYS; 287} 288 289static int mgmt_resolve_name(int index, bdaddr_t *bdaddr) 290{ 291 char addr[18]; 292 293 ba2str(bdaddr, addr); 294 DBG("index %d addr %s", index, addr); 295 296 return -ENOSYS; 297} 298 299static int mgmt_set_name(int index, const char *name) 300{ 301 DBG("index %d, name %s", index, name); 302 return -ENOSYS; 303} 304 305static int mgmt_read_name(int index) 306{ 307 DBG("index %d", index); 308 return -ENOSYS; 309} 310 311static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr) 312{ 313 char addr[18]; 314 315 ba2str(bdaddr, addr); 316 DBG("index %d addr %s", index, addr); 317 318 return -ENOSYS; 319} 320 321static int mgmt_fast_connectable(int index, gboolean enable) 322{ 323 DBG("index %d enable %d", index, enable); 324 return -ENOSYS; 325} 326 327static int mgmt_read_clock(int index, int handle, int which, int timeout, 328 uint32_t *clock, uint16_t *accuracy) 329{ 330 DBG("index %d handle %d which %d timeout %d", index, handle, 331 which, timeout); 332 return -ENOSYS; 333} 334 335static int mgmt_conn_handle(int index, const bdaddr_t *bdaddr, int *handle) 336{ 337 char addr[18]; 338 339 ba2str(bdaddr, addr); 340 DBG("index %d addr %s", index, addr); 341 342 return -ENOSYS; 343} 344 345static int mgmt_write_eir_data(int index, uint8_t *data) 346{ 347 DBG("index %d", index); 348 return -ENOSYS; 349} 350 351static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr) 352{ 353 char addr[18]; 354 355 ba2str(bdaddr, addr); 356 DBG("index %d addr %s", index, addr); 357 358 return -ENOSYS; 359} 360 361static int mgmt_set_event_mask(int index, uint8_t *events, size_t count) 362{ 363 DBG("index %d", index); 364 return -ENOSYS; 365} 366 367static int mgmt_write_inq_mode(int index, uint8_t mode) 368{ 369 DBG("index %d mode %u", index, mode); 370 return -ENOSYS; 371} 372 373static int mgmt_read_inq_tx_pwr(int index) 374{ 375 DBG("index %d", index); 376 return -ENOSYS; 377} 378 379static int mgmt_block_device(int index, bdaddr_t *bdaddr) 380{ 381 char addr[18]; 382 383 ba2str(bdaddr, addr); 384 DBG("index %d addr %s", index, addr); 385 386 return -ENOSYS; 387} 388 389static int mgmt_unblock_device(int index, bdaddr_t *bdaddr) 390{ 391 char addr[18]; 392 393 ba2str(bdaddr, addr); 394 DBG("index %d addr %s", index, addr); 395 396 return -ENOSYS; 397} 398 399static int mgmt_get_conn_list(int index, GSList **conns) 400{ 401 DBG("index %d", index); 402 return -ENOSYS; 403} 404 405static int mgmt_read_local_version(int index, struct hci_version *ver) 406{ 407 DBG("index %d", index); 408 return -ENOSYS; 409} 410 411static int mgmt_read_local_features(int index, uint8_t *features) 412{ 413 DBG("index %d", index); 414 return -ENOSYS; 415} 416 417static int mgmt_read_local_ext_features(int index) 418{ 419 DBG("index %d", index); 420 return -ENOSYS; 421} 422 423static int mgmt_init_ssp_mode(int index, uint8_t *mode) 424{ 425 DBG("index %d", index); 426 return -ENOSYS; 427} 428 429static int mgmt_read_link_policy(int index) 430{ 431 DBG("index %d", index); 432 return -ENOSYS; 433} 434 435static int mgmt_disconnect(int index, uint16_t handle) 436{ 437 DBG("index %d handle %u", index, handle); 438 return -ENOSYS; 439} 440 441static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr) 442{ 443 char addr[18]; 444 445 ba2str(bdaddr, addr); 446 DBG("index %d addr %s", index, addr); 447 448 return -ENOSYS; 449} 450 451static int mgmt_request_authentication(int index, uint16_t handle, 452 uint8_t *status) 453{ 454 DBG("index %d handle %u", index, handle); 455 return -ENOSYS; 456} 457 458static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin) 459{ 460 char addr[18]; 461 462 ba2str(bdaddr, addr); 463 DBG("index %d addr %s pin %s", index, addr, pin); 464 465 return -ENOSYS; 466} 467 468static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success) 469{ 470 char addr[18]; 471 472 ba2str(bdaddr, addr); 473 DBG("index %d addr %s success %d", index, addr, success); 474 475 return -ENOSYS; 476} 477 478static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey) 479{ 480 char addr[18]; 481 482 ba2str(bdaddr, addr); 483 DBG("index %d addr %s passkey %06u", index, addr, passkey); 484 485 return -ENOSYS; 486} 487 488static int mgmt_get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth) 489{ 490 char addr[18]; 491 492 ba2str(bdaddr, addr); 493 DBG("index %d addr %s", index, addr); 494 495 return -ENOSYS; 496} 497 498static int mgmt_read_scan_enable(int index) 499{ 500 DBG("index %d", index); 501 return -ENOSYS; 502} 503 504static int mgmt_read_ssp_mode(int index) 505{ 506 DBG("index %d", index); 507 return -ENOSYS; 508} 509 510static int mgmt_write_le_host(int index, uint8_t le, uint8_t simul) 511{ 512 DBG("index %d le %u simul %u", index, le, simul); 513 return -ENOSYS; 514} 515 516static int mgmt_get_remote_version(int index, uint16_t handle, 517 gboolean delayed) 518{ 519 DBG("index %d handle %u delayed %d", index, handle, delayed); 520 return -ENOSYS; 521} 522 523static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb, 524 gpointer user_data) 525{ 526 char addr[18]; 527 528 ba2str(dst, addr); 529 DBG("index %d addr %s", index, addr); 530 531 return -ENOSYS; 532} 533 534static struct btd_adapter_ops mgmt_ops = { 535 .setup = mgmt_setup, 536 .cleanup = mgmt_cleanup, 537 .start = mgmt_start, 538 .stop = mgmt_stop, 539 .set_powered = mgmt_powered, 540 .set_connectable = mgmt_connectable, 541 .set_discoverable = mgmt_discoverable, 542 .set_limited_discoverable = mgmt_set_limited_discoverable, 543 .start_inquiry = mgmt_start_inquiry, 544 .stop_inquiry = mgmt_stop_inquiry, 545 .start_scanning = mgmt_start_scanning, 546 .stop_scanning = mgmt_stop_scanning, 547 .resolve_name = mgmt_resolve_name, 548 .cancel_resolve_name = mgmt_cancel_resolve_name, 549 .set_name = mgmt_set_name, 550 .read_name = mgmt_read_name, 551 .set_class = mgmt_set_class, 552 .set_fast_connectable = mgmt_fast_connectable, 553 .read_clock = mgmt_read_clock, 554 .get_conn_handle = mgmt_conn_handle, 555 .write_eir_data = mgmt_write_eir_data, 556 .read_bdaddr = mgmt_read_bdaddr, 557 .set_event_mask = mgmt_set_event_mask, 558 .write_inq_mode = mgmt_write_inq_mode, 559 .read_inq_tx_pwr = mgmt_read_inq_tx_pwr, 560 .block_device = mgmt_block_device, 561 .unblock_device = mgmt_unblock_device, 562 .get_conn_list = mgmt_get_conn_list, 563 .read_local_version = mgmt_read_local_version, 564 .read_local_features = mgmt_read_local_features, 565 .read_local_ext_features = mgmt_read_local_ext_features, 566 .init_ssp_mode = mgmt_init_ssp_mode, 567 .read_link_policy = mgmt_read_link_policy, 568 .disconnect = mgmt_disconnect, 569 .remove_bonding = mgmt_remove_bonding, 570 .request_authentication = mgmt_request_authentication, 571 .pincode_reply = mgmt_pincode_reply, 572 .confirm_reply = mgmt_confirm_reply, 573 .passkey_reply = mgmt_passkey_reply, 574 .get_auth_info = mgmt_get_auth_info, 575 .read_scan_enable = mgmt_read_scan_enable, 576 .read_ssp_mode = mgmt_read_ssp_mode, 577 .write_le_host = mgmt_write_le_host, 578 .get_remote_version = mgmt_get_remote_version, 579 .encrypt_link = mgmt_encrypt_link, 580}; 581 582static int mgmt_init(void) 583{ 584 return btd_register_adapter_ops(&mgmt_ops, TRUE); 585} 586 587static void mgmt_exit(void) 588{ 589 btd_adapter_cleanup_ops(&mgmt_ops); 590} 591 592BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION, 593 BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit) 594