1 /* 2 * link_control.c 3 * 4 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: link_control.c,v 1.4 2003/08/18 19:19:54 max Exp $ 29 * $FreeBSD$ 30 */ 31 32 #include <bluetooth.h> 33 #include <errno.h> 34 #include <stdio.h> 35 #include <string.h> 36 #include "hccontrol.h" 37 38 static void hci_inquiry_response (int n, uint8_t **b); 39 40 /* Send Inquiry command to the unit */ 41 static int 42 hci_inquiry(int s, int argc, char **argv) 43 { 44 int n0, n1, n2, timo; 45 uint8_t b[512]; 46 ng_hci_inquiry_cp cp; 47 ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 48 49 /* set defaults */ 50 cp.lap[2] = 0x9e; 51 cp.lap[1] = 0x8b; 52 cp.lap[0] = 0x33; 53 cp.inquiry_length = 5; 54 cp.num_responses = 8; 55 56 /* parse command parameters */ 57 switch (argc) { 58 case 3: 59 /* number of responses, range 0x00 - 0xff */ 60 if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 0xff) 61 return (USAGE); 62 63 cp.num_responses = (n0 & 0xff); 64 65 case 2: 66 /* inquiry length (N * 1.28) sec, range 0x01 - 0x30 */ 67 if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x1 || n0 > 0x30) 68 return (USAGE); 69 70 cp.inquiry_length = (n0 & 0xff); 71 72 case 1: 73 /* LAP */ 74 if (sscanf(argv[0], "%x:%x:%x", &n2, &n1, &n0) != 3) 75 return (USAGE); 76 77 cp.lap[0] = (n0 & 0xff); 78 cp.lap[1] = (n1 & 0xff); 79 cp.lap[2] = (n2 & 0xff); 80 81 case 0: 82 /* use defaults */ 83 break; 84 85 default: 86 return (USAGE); 87 } 88 89 /* send request and expect status back */ 90 n0 = sizeof(b); 91 if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 92 NG_HCI_OCF_INQUIRY), (char const *) &cp, sizeof(cp), 93 b, &n0) == ERROR) 94 return (ERROR); 95 96 if (*b != 0x00) 97 return (FAILED); 98 99 timo = timeout; 100 timeout = cp.inquiry_length * 1.28 + 1; 101 102 wait_for_more: 103 /* wait for inquiry events */ 104 n0 = sizeof(b); 105 if (hci_recv(s, b, &n0) == ERROR) { 106 timeout = timo; 107 return (ERROR); 108 } 109 110 if (n0 < sizeof(*e)) { 111 timeout = timo; 112 errno = EIO; 113 return (ERROR); 114 } 115 116 switch (e->event) { 117 case NG_HCI_EVENT_INQUIRY_RESULT: { 118 ng_hci_inquiry_result_ep *ir = 119 (ng_hci_inquiry_result_ep *)(e + 1); 120 uint8_t *r = (uint8_t *)(ir + 1); 121 122 fprintf(stdout, "Inquiry result, num_responses=%d\n", 123 ir->num_responses); 124 125 for (n0 = 0; n0 < ir->num_responses; n0++) 126 hci_inquiry_response(n0, &r); 127 128 goto wait_for_more; 129 } 130 131 case NG_HCI_EVENT_INQUIRY_COMPL: 132 fprintf(stdout, "Inquiry complete. Status: %s [%#02x]\n", 133 hci_status2str(*(b + sizeof(*e))), *(b + sizeof(*e))); 134 break; 135 136 default: 137 goto wait_for_more; 138 } 139 140 timeout = timo; 141 142 return (OK); 143 } /* hci_inquiry */ 144 145 /* Print Inquiry_Result event */ 146 static void 147 hci_inquiry_response(int n, uint8_t **b) 148 { 149 struct inquiry_response { 150 bdaddr_t bdaddr; 151 uint8_t page_scan_rep_mode; 152 uint8_t page_scan_period_mode; 153 uint8_t page_scan_mode; 154 uint8_t class[NG_HCI_CLASS_SIZE]; 155 uint16_t clock_offset; 156 } *ir = (struct inquiry_response *)(*b); 157 158 fprintf(stdout, "Inquiry result #%d\n", n); 159 fprintf(stdout, "\tBD_ADDR: %s\n", hci_bdaddr2str(&ir->bdaddr)); 160 fprintf(stdout, "\tPage Scan Rep. Mode: %#02x\n", 161 ir->page_scan_rep_mode); 162 fprintf(stdout, "\tPage Scan Period Mode: %#02x\n", 163 ir->page_scan_period_mode); 164 fprintf(stdout, "\tPage Scan Mode: %#02x\n", 165 ir->page_scan_mode); 166 fprintf(stdout, "\tClass: %02x:%02x:%02x\n", 167 ir->class[2], ir->class[1], ir->class[0]); 168 fprintf(stdout, "\tClock offset: %#04x\n", 169 le16toh(ir->clock_offset)); 170 171 *b += sizeof(*ir); 172 } /* hci_inquiry_response */ 173 174 /* Send Create_Connection command to the unit */ 175 static int 176 hci_create_connection(int s, int argc, char **argv) 177 { 178 int n0; 179 char b[512]; 180 ng_hci_create_con_cp cp; 181 ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 182 183 /* Set defaults */ 184 memset(&cp, 0, sizeof(cp)); 185 cp.pkt_type = htole16( NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 | 186 NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 | 187 NG_HCI_PKT_DM5); 188 cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0; 189 cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE; 190 cp.clock_offset = 0; 191 cp.accept_role_switch = 1; 192 193 /* parse command parameters */ 194 switch (argc) { 195 case 6: 196 /* accept role switch */ 197 if (sscanf(argv[5], "%d", &n0) != 1) 198 return (USAGE); 199 200 cp.accept_role_switch = n0 ? 1 : 0; 201 202 case 5: 203 /* clock offset */ 204 if (sscanf(argv[4], "%d", &n0) != 1) 205 return (USAGE); 206 207 cp.clock_offset = (n0 & 0xffff); 208 cp.clock_offset = htole16(cp.clock_offset); 209 210 case 4: 211 /* page scan mode */ 212 if (sscanf(argv[3], "%d", &n0) != 1 || n0 < 0 || n0 > 3) 213 return (USAGE); 214 215 cp.page_scan_mode = (n0 & 0xff); 216 217 case 3: 218 /* page scan rep mode */ 219 if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0 || n0 > 2) 220 return (USAGE); 221 222 cp.page_scan_rep_mode = (n0 & 0xff); 223 224 case 2: 225 /* packet type */ 226 if (sscanf(argv[1], "%x", &n0) != 1) 227 return (USAGE); 228 229 n0 &= ( NG_HCI_PKT_DM1 | NG_HCI_PKT_DH1 | 230 NG_HCI_PKT_DM3 | NG_HCI_PKT_DH3 | 231 NG_HCI_PKT_DM5); 232 if (n0 == 0) 233 return (USAGE); 234 235 cp.pkt_type = (n0 & 0xffff); 236 cp.pkt_type = htole16(cp.pkt_type); 237 238 case 1: 239 /* BD_ADDR */ 240 if (!bt_aton(argv[0], &cp.bdaddr)) { 241 struct hostent *he = NULL; 242 243 if ((he = bt_gethostbyname(argv[0])) == NULL) 244 return (USAGE); 245 246 memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr)); 247 } 248 break; 249 250 default: 251 return (USAGE); 252 } 253 254 /* send request and expect status response */ 255 n0 = sizeof(b); 256 if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 257 NG_HCI_OCF_CREATE_CON), 258 (char const *) &cp, sizeof(cp), b, &n0) == ERROR) 259 return (ERROR); 260 261 if (*b != 0x00) 262 return (FAILED); 263 264 /* wait for event */ 265 again: 266 n0 = sizeof(b); 267 if (hci_recv(s, b, &n0) == ERROR) 268 return (ERROR); 269 if (n0 < sizeof(*e)) { 270 errno = EIO; 271 return (ERROR); 272 } 273 274 if (e->event == NG_HCI_EVENT_CON_COMPL) { 275 ng_hci_con_compl_ep *ep = (ng_hci_con_compl_ep *)(e + 1); 276 277 if (ep->status != 0x00) { 278 fprintf(stdout, "Status: %s [%#02x]\n", 279 hci_status2str(ep->status), ep->status); 280 return (FAILED); 281 } 282 283 fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr)); 284 fprintf(stdout, "Connection handle: %d\n", 285 le16toh(ep->con_handle)); 286 fprintf(stdout, "Encryption mode: %s [%d]\n", 287 hci_encrypt2str(ep->encryption_mode, 0), 288 ep->encryption_mode); 289 } else 290 goto again; 291 292 return (OK); 293 } /* hci_create_connection */ 294 295 /* Send Disconnect command to the unit */ 296 static int 297 hci_disconnect(int s, int argc, char **argv) 298 { 299 int n; 300 char b[512]; 301 ng_hci_discon_cp cp; 302 ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 303 304 /* Set defaults */ 305 memset(&cp, 0, sizeof(cp)); 306 cp.reason = 0x13; 307 308 /* parse command parameters */ 309 switch (argc) { 310 case 2: 311 /* reason */ 312 if (sscanf(argv[1], "%d", &n) != 1 || n <= 0x00 || n > 0xff) 313 return (USAGE); 314 315 cp.reason = (uint8_t) (n & 0xff); 316 317 case 1: 318 /* connection handle */ 319 if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 320 return (USAGE); 321 322 cp.con_handle = (uint16_t) (n & 0x0fff); 323 cp.con_handle = htole16(cp.con_handle); 324 break; 325 326 default: 327 return (USAGE); 328 } 329 330 /* send request and expect status response */ 331 n = sizeof(b); 332 if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 333 NG_HCI_OCF_DISCON), 334 (char const *) &cp, sizeof(cp), b, &n) == ERROR) 335 return (ERROR); 336 337 if (*b != 0x00) 338 return (FAILED); 339 340 /* wait for event */ 341 again: 342 n = sizeof(b); 343 if (hci_recv(s, b, &n) == ERROR) 344 return (ERROR); 345 if (n < sizeof(*e)) { 346 errno = EIO; 347 return (ERROR); 348 } 349 350 if (e->event == NG_HCI_EVENT_DISCON_COMPL) { 351 ng_hci_discon_compl_ep *ep = (ng_hci_discon_compl_ep *)(e + 1); 352 353 if (ep->status != 0x00) { 354 fprintf(stdout, "Status: %s [%#02x]\n", 355 hci_status2str(ep->status), ep->status); 356 return (FAILED); 357 } 358 359 fprintf(stdout, "Connection handle: %d\n", 360 le16toh(ep->con_handle)); 361 fprintf(stdout, "Reason: %s [%#02x]\n", 362 hci_status2str(ep->reason), ep->reason); 363 } else 364 goto again; 365 366 return (OK); 367 } /* hci_diconnect */ 368 369 /* Send Add_SCO_Connection command to the unit */ 370 static int 371 hci_add_sco_connection(int s, int argc, char **argv) 372 { 373 int n; 374 char b[512]; 375 ng_hci_add_sco_con_cp cp; 376 ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 377 378 /* Set defaults */ 379 memset(&cp, 0, sizeof(cp)); 380 cp.pkt_type = htole16(NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3); 381 382 /* parse command parameters */ 383 switch (argc) { 384 case 2: 385 /* packet type */ 386 if (sscanf(argv[1], "%x", &n) != 1) 387 return (USAGE); 388 389 n &= (NG_HCI_PKT_HV1 | NG_HCI_PKT_HV2 | NG_HCI_PKT_HV3); 390 if (n == 0) 391 return (USAGE); 392 393 cp.pkt_type = (uint16_t) (n & 0x0fff); 394 cp.pkt_type = htole16(cp.pkt_type); 395 396 case 1: 397 /* acl connection handle */ 398 if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 399 return (USAGE); 400 401 cp.con_handle = (uint16_t) (n & 0x0fff); 402 cp.con_handle = htole16(cp.con_handle); 403 break; 404 405 default: 406 return (USAGE); 407 } 408 409 /* send request and expect status response */ 410 n = sizeof(b); 411 if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 412 NG_HCI_OCF_ADD_SCO_CON), 413 (char const *) &cp, sizeof(cp), b, &n) == ERROR) 414 return (ERROR); 415 416 if (*b != 0x00) 417 return (FAILED); 418 419 /* wait for event */ 420 again: 421 n = sizeof(b); 422 if (hci_recv(s, b, &n) == ERROR) 423 return (ERROR); 424 if (n < sizeof(*e)) { 425 errno = EIO; 426 return (ERROR); 427 } 428 429 if (e->event == NG_HCI_EVENT_CON_COMPL) { 430 ng_hci_con_compl_ep *ep = (ng_hci_con_compl_ep *)(e + 1); 431 432 if (ep->status != 0x00) { 433 fprintf(stdout, "Status: %s [%#02x]\n", 434 hci_status2str(ep->status), ep->status); 435 return (FAILED); 436 } 437 438 fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr)); 439 fprintf(stdout, "Connection handle: %d\n", 440 le16toh(ep->con_handle)); 441 fprintf(stdout, "Encryption mode: %s [%d]\n", 442 hci_encrypt2str(ep->encryption_mode, 0), 443 ep->encryption_mode); 444 } else 445 goto again; 446 447 return (OK); 448 } /* Add_SCO_Connection */ 449 450 /* Send Change_Connection_Packet_Type command to the unit */ 451 static int 452 hci_change_connection_packet_type(int s, int argc, char **argv) 453 { 454 int n; 455 char b[512]; 456 ng_hci_change_con_pkt_type_cp cp; 457 ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 458 459 switch (argc) { 460 case 2: 461 /* connection handle */ 462 if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 463 return (USAGE); 464 465 cp.con_handle = (uint16_t) (n & 0x0fff); 466 cp.con_handle = htole16(cp.con_handle); 467 468 /* packet type */ 469 if (sscanf(argv[1], "%x", &n) != 1) 470 return (USAGE); 471 472 cp.pkt_type = (uint16_t) (n & 0xffff); 473 cp.pkt_type = htole16(cp.pkt_type); 474 break; 475 476 default: 477 return (USAGE); 478 } 479 480 /* send request and expect status response */ 481 n = sizeof(b); 482 if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 483 NG_HCI_OCF_CHANGE_CON_PKT_TYPE), 484 (char const *) &cp, sizeof(cp), b, &n) == ERROR) 485 return (ERROR); 486 487 if (*b != 0x00) 488 return (FAILED); 489 490 /* wait for event */ 491 again: 492 n = sizeof(b); 493 if (hci_recv(s, b, &n) == ERROR) 494 return (ERROR); 495 if (n < sizeof(*e)) { 496 errno = EIO; 497 return (ERROR); 498 } 499 500 if (e->event == NG_HCI_EVENT_CON_PKT_TYPE_CHANGED) { 501 ng_hci_con_pkt_type_changed_ep *ep = 502 (ng_hci_con_pkt_type_changed_ep *)(e + 1); 503 504 if (ep->status != 0x00) { 505 fprintf(stdout, "Status: %s [%#02x]\n", 506 hci_status2str(ep->status), ep->status); 507 return (FAILED); 508 } 509 510 fprintf(stdout, "Connection handle: %d\n", 511 le16toh(ep->con_handle)); 512 fprintf(stdout, "Packet type: %#04x\n", 513 le16toh(ep->pkt_type)); 514 } else 515 goto again; 516 517 return (OK); 518 } /* hci_change_connection_packet_type */ 519 520 /* Send Remote_Name_Request command to the unit */ 521 static int 522 hci_remote_name_request(int s, int argc, char **argv) 523 { 524 int n0; 525 char b[512]; 526 ng_hci_remote_name_req_cp cp; 527 ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 528 529 memset(&cp, 0, sizeof(cp)); 530 cp.page_scan_rep_mode = NG_HCI_SCAN_REP_MODE0; 531 cp.page_scan_mode = NG_HCI_MANDATORY_PAGE_SCAN_MODE; 532 533 /* parse command parameters */ 534 switch (argc) { 535 case 4: 536 /* clock_offset */ 537 if (sscanf(argv[3], "%x", &n0) != 1) 538 return (USAGE); 539 540 cp.clock_offset = (n0 & 0xffff); 541 cp.clock_offset = htole16(cp.clock_offset); 542 543 case 3: 544 /* page_scan_mode */ 545 if (sscanf(argv[2], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x03) 546 return (USAGE); 547 548 cp.page_scan_mode = (n0 & 0xff); 549 550 case 2: 551 /* page_scan_rep_mode */ 552 if (sscanf(argv[1], "%d", &n0) != 1 || n0 < 0x00 || n0 > 0x02) 553 return (USAGE); 554 555 cp.page_scan_rep_mode = (n0 & 0xff); 556 557 case 1: 558 /* BD_ADDR */ 559 if (!bt_aton(argv[0], &cp.bdaddr)) { 560 struct hostent *he = NULL; 561 562 if ((he = bt_gethostbyname(argv[0])) == NULL) 563 return (USAGE); 564 565 memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr)); 566 } 567 break; 568 569 default: 570 return (USAGE); 571 } 572 573 /* send request and expect status response */ 574 n0 = sizeof(b); 575 if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 576 NG_HCI_OCF_REMOTE_NAME_REQ), 577 (char const *) &cp, sizeof(cp), b, &n0) == ERROR) 578 return (ERROR); 579 580 if (*b != 0x00) 581 return (FAILED); 582 583 /* wait for event */ 584 again: 585 n0 = sizeof(b); 586 if (hci_recv(s, b, &n0) == ERROR) 587 return (ERROR); 588 if (n0 < sizeof(*e)) { 589 errno = EIO; 590 return (ERROR); 591 } 592 593 if (e->event == NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL) { 594 ng_hci_remote_name_req_compl_ep *ep = 595 (ng_hci_remote_name_req_compl_ep *)(e + 1); 596 597 if (ep->status != 0x00) { 598 fprintf(stdout, "Status: %s [%#02x]\n", 599 hci_status2str(ep->status), ep->status); 600 return (FAILED); 601 } 602 603 fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr)); 604 fprintf(stdout, "Name: %s\n", ep->name); 605 } else 606 goto again; 607 608 return (OK); 609 } /* hci_remote_name_request */ 610 611 /* Send Read_Remote_Supported_Features command to the unit */ 612 static int 613 hci_read_remote_supported_features(int s, int argc, char **argv) 614 { 615 int n; 616 char b[512]; 617 ng_hci_read_remote_features_cp cp; 618 ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 619 char buffer[1024]; 620 621 /* parse command parameters */ 622 switch (argc) { 623 case 1: 624 /* connecton handle */ 625 if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff) 626 return (USAGE); 627 628 cp.con_handle = (n & 0x0fff); 629 cp.con_handle = htole16(cp.con_handle); 630 break; 631 632 default: 633 return (USAGE); 634 } 635 636 /* send request and expect status response */ 637 n = sizeof(b); 638 if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 639 NG_HCI_OCF_READ_REMOTE_FEATURES), 640 (char const *) &cp, sizeof(cp), b, &n) == ERROR) 641 return (ERROR); 642 643 if (*b != 0x00) 644 return (FAILED); 645 646 /* wait for event */ 647 again: 648 n = sizeof(b); 649 if (hci_recv(s, b, &n) == ERROR) 650 return (ERROR); 651 652 if (n < sizeof(*e)) { 653 errno = EIO; 654 return (ERROR); 655 } 656 657 if (e->event == NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL) { 658 ng_hci_read_remote_features_compl_ep *ep = 659 (ng_hci_read_remote_features_compl_ep *)(e + 1); 660 661 if (ep->status != 0x00) { 662 fprintf(stdout, "Status: %s [%#02x]\n", 663 hci_status2str(ep->status), ep->status); 664 return (FAILED); 665 } 666 667 fprintf(stdout, "Connection handle: %d\n", 668 le16toh(ep->con_handle)); 669 fprintf(stdout, "Features: "); 670 for (n = 0; n < sizeof(ep->features); n++) 671 fprintf(stdout, "%#02x ", ep->features[n]); 672 fprintf(stdout, "\n%s\n", hci_features2str(ep->features, 673 buffer, sizeof(buffer))); 674 } else 675 goto again; 676 677 return (OK); 678 } /* hci_read_remote_supported_features */ 679 680 /* Send Read_Remote_Version_Information command to the unit */ 681 static int 682 hci_read_remote_version_information(int s, int argc, char **argv) 683 { 684 int n; 685 char b[512]; 686 ng_hci_read_remote_ver_info_cp cp; 687 ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 688 689 /* parse command parameters */ 690 switch (argc) { 691 case 1: 692 /* connecton handle */ 693 if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff) 694 return (USAGE); 695 696 cp.con_handle = (n & 0x0fff); 697 cp.con_handle = htole16(cp.con_handle); 698 break; 699 700 default: 701 return (USAGE); 702 } 703 704 /* send request and expect status response */ 705 n = sizeof(b); 706 if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 707 NG_HCI_OCF_READ_REMOTE_VER_INFO), 708 (char const *) &cp, sizeof(cp), b, &n) == ERROR) 709 return (ERROR); 710 711 if (*b != 0x00) 712 return (FAILED); 713 714 /* wait for event */ 715 again: 716 n = sizeof(b); 717 if (hci_recv(s, b, &n) == ERROR) 718 return (ERROR); 719 720 if (n < sizeof(*e)) { 721 errno = EIO; 722 return (ERROR); 723 } 724 725 if (e->event == NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL) { 726 ng_hci_read_remote_ver_info_compl_ep *ep = 727 (ng_hci_read_remote_ver_info_compl_ep *)(e + 1); 728 729 if (ep->status != 0x00) { 730 fprintf(stdout, "Status: %s [%#02x]\n", 731 hci_status2str(ep->status), ep->status); 732 return (FAILED); 733 } 734 735 ep->manufacturer = le16toh(ep->manufacturer); 736 737 fprintf(stdout, "Connection handle: %d\n", 738 le16toh(ep->con_handle)); 739 fprintf(stdout, "LMP version: %#02x\n", ep->lmp_version); 740 fprintf(stdout, "LMP sub-version: %#04x\n", 741 le16toh(ep->lmp_subversion)); 742 fprintf(stdout, "Manufacturer: %s [%#04x]\n", 743 hci_manufacturer2str(ep->manufacturer), 744 ep->manufacturer); 745 } else 746 goto again; 747 748 return (OK); 749 } /* hci_read_remote_version_information */ 750 751 /* Send Read_Clock_Offset command to the unit */ 752 static int 753 hci_read_clock_offset(int s, int argc, char **argv) 754 { 755 int n; 756 char b[512]; 757 ng_hci_read_clock_offset_cp cp; 758 ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 759 760 /* parse command parameters */ 761 switch (argc) { 762 case 1: 763 /* connecton handle */ 764 if (sscanf(argv[0], "%d", &n) != 1 || n < 0 || n > 0x0eff) 765 return (USAGE); 766 767 cp.con_handle = (n & 0x0fff); 768 cp.con_handle = htole16(cp.con_handle); 769 break; 770 771 default: 772 return (USAGE); 773 } 774 775 /* send request and expect status response */ 776 n = sizeof(b); 777 if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 778 NG_HCI_OCF_READ_CLOCK_OFFSET), 779 (char const *) &cp, sizeof(cp), b, &n) == ERROR) 780 return (ERROR); 781 782 if (*b != 0x00) 783 return (FAILED); 784 785 /* wait for event */ 786 again: 787 n = sizeof(b); 788 if (hci_recv(s, b, &n) == ERROR) 789 return (ERROR); 790 791 if (n < sizeof(*e)) { 792 errno = EIO; 793 return (ERROR); 794 } 795 796 if (e->event == NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL) { 797 ng_hci_read_clock_offset_compl_ep *ep = 798 (ng_hci_read_clock_offset_compl_ep *)(e + 1); 799 800 if (ep->status != 0x00) { 801 fprintf(stdout, "Status: %s [%#02x]\n", 802 hci_status2str(ep->status), ep->status); 803 return (FAILED); 804 } 805 806 fprintf(stdout, "Connection handle: %d\n", 807 le16toh(ep->con_handle)); 808 fprintf(stdout, "Clock offset: %#04x\n", 809 le16toh(ep->clock_offset)); 810 } else 811 goto again; 812 813 return (OK); 814 } /* hci_read_clock_offset */ 815 816 struct hci_command link_control_commands[] = { 817 { 818 "inquiry <LAP> <inquiry_length> <num_reponses>", 819 "\nThis command will cause the Bluetooth unit to enter Inquiry Mode.\n" \ 820 "Inquiry Mode is used to discover other nearby Bluetooth units. The LAP\n" \ 821 "input parameter contains the LAP from which the inquiry access code shall\n" \ 822 "be derived when the inquiry procedure is made. The Inquiry_Length parameter\n"\ 823 "specifies the total duration of the Inquiry Mode and, when this time\n" \ 824 "expires, Inquiry will be halted. The Num_Responses parameter specifies the\n" \ 825 "number of responses that can be received before the Inquiry is halted.\n\n" \ 826 "\t<LAP> - xx:xx:xx; 9e:8b:33 (GIAC), 93:8b:00 (LDIAC)\n" \ 827 "\t<inquiry_length> - dd; total length == dd * 1.28 sec\n" \ 828 "\t<num_responses> - dd", 829 &hci_inquiry 830 }, 831 { 832 "create_connection <BD_ADDR> <pkt> <rep_mode> <ps_mode> <clck_off> <role_sw>", 833 "" \ 834 "\t<BD_ADDR> - remote unit address\n\n" \ 835 "\t<pkt> - xxxx; packet type\n" \ 836 "" \ 837 "\t\tACL packets\n" \ 838 "\t\t-----------\n" \ 839 "\t\t0x0008 DM1\n" \ 840 "\t\t0x0010 DH1\n" \ 841 "\t\t0x0400 DM3\n" \ 842 "\t\t0x0800 DH3\n" \ 843 "\t\t0x4000 DM5\n" \ 844 "\t\t0x8000 DH5\n\n" \ 845 "" \ 846 "\trep_mode - d; page scan repetition mode\n" \ 847 "" \ 848 "\t\tPage scan repetition modes\n" \ 849 "\t\t--------------------------\n" \ 850 "\t\t0 Page scan repetition mode 0\n" \ 851 "\t\t1 Page scan repetition mode 1\n" \ 852 "\t\t2 Page scan repetition mode 2\n" \ 853 "\n" \ 854 "\tps_mode - d; Page scan mode\n" \ 855 "" \ 856 "\t\tPage scan modes\n" \ 857 "\t\t---------------\n" \ 858 "\t\t0 Mandatory page scan mode\n" \ 859 "\t\t1 Optional page scan mode1\n" \ 860 "\t\t2 Optional page scan mode2\n" \ 861 "\t\t3 Optional page scan mode3\n" \ 862 "\n" \ 863 "\tclck_off - dddd; clock offset. Use 0 if unknown\n\n" \ 864 "\trole_sw - d; allow (1) or deny role switch\n", 865 &hci_create_connection 866 }, 867 { 868 "disconnect <connection_handle> <reason>", 869 "\nThe Disconnection command is used to terminate an existing connection.\n" \ 870 "The connection handle command parameter indicates which connection is to\n" \ 871 "be disconnected. The Reason command parameter indicates the reason for\n" \ 872 "ending the connection.\n\n" \ 873 "\t<connection_handle> - dddd; connection handle\n" \ 874 "\t<reason> - dd; reason; usually 19 (0x13) - user ended;\n" \ 875 "\t also 0x05, 0x13-0x15, 0x1A, 0x29", 876 &hci_disconnect 877 }, 878 { 879 "add_sco_connection <acl connection handle> <packet type>", 880 "This command will cause the link manager to create a SCO connection using\n" \ 881 "the ACL connection specified by the connection handle command parameter.\n" \ 882 "The Link Manager will determine how the new connection is established. This\n"\ 883 "connection is determined by the current state of the device, its piconet,\n" \ 884 "and the state of the device to be connected. The packet type command parameter\n" \ 885 "specifies which packet types the Link Manager should use for the connection.\n"\ 886 "The Link Manager must only use the packet type(s) specified by the packet\n" \ 887 "type command parameter for sending HCI SCO data packets. Multiple packet\n" \ 888 "types may be specified for the packet type command parameter by performing\n" \ 889 "a bitwise OR operation of the different packet types. Note: An SCO connection\n" \ 890 "can only be created when an ACL connection already exists and when it is\n" \ 891 "not put in park mode.\n\n" \ 892 "\t<connection_handle> - dddd; ACL connection handle\n" \ 893 "\t<packet_type> - xxxx; packet type\n" \ 894 "" \ 895 "\t\tSCO packets\n" \ 896 "\t\t-----------\n" \ 897 "\t\t0x0020 HV1\n" \ 898 "\t\t0x0040 HV2\n" \ 899 "\t\t0x0080 HV3\n", 900 &hci_add_sco_connection 901 }, 902 { 903 "change_connection_packet_type <connection_hande> <packet_type>", 904 "The Change_Connection_Packet_Type command is used to change which packet\n" \ 905 "types can be used for a connection that is currently established. This\n" \ 906 "allows current connections to be dynamically modified to support different\n" \ 907 "types of user data. The Packet_Type command parameter specifies which\n" \ 908 "packet types the Link Manager can use for the connection. Multiple packet\n" \ 909 "types may be specified for the Packet_Type command parameter by bitwise OR\n" \ 910 "operation of the different packet types.\n\n" \ 911 "\t<connection_handle> - dddd; connection handle\n" \ 912 "\t<packet_type> - xxxx; packet type mask\n" \ 913 "" \ 914 "\t\tACL packets\n" \ 915 "\t\t-----------\n" \ 916 "\t\t0x0008 DM1\n" \ 917 "\t\t0x0010 DH1\n" \ 918 "\t\t0x0400 DM3\n" \ 919 "\t\t0x0800 DH3\n" \ 920 "\t\t0x4000 DM5\n" \ 921 "\t\t0x8000 DH5\n\n" \ 922 "" \ 923 "\t\tSCO packets\n" \ 924 "\t\t-----------\n" \ 925 "\t\t0x0020 HV1\n" \ 926 "\t\t0x0040 HV2\n" \ 927 "\t\t0x0080 HV3\n" \ 928 "", 929 &hci_change_connection_packet_type 930 }, 931 { 932 "remote_name_request <bdaddr> <ps_rep_mode> <ps_mode> <clock_offset>", 933 "\nThe Remote_Name_Request command is used to obtain the user-friendly\n" \ 934 "name of another Bluetooth unit.\n\n" \ 935 "\t<bdaddr> - xx:xx:xx:xx:xx:xx remote unit BD_ADDR\n" \ 936 "\t<ps_rep_mode> - dd; page scan repetition mode [0-2]\n" \ 937 "\t<ps_mode> - dd; page scan mode [0-3]\n" \ 938 "\t<clock_offset> - xxxx; clock offset [0 - 0xffff]", 939 &hci_remote_name_request 940 }, 941 { 942 "read_remote_supported_features <connection_handle>", 943 "\nThis command requests a list of the supported features for the remote\n" \ 944 "unit identified by the connection handle parameter. The connection handle\n" \ 945 "must be a connection handle for an ACL connection.\n\n" \ 946 "\t<connection_handle> - dddd; connection handle", 947 &hci_read_remote_supported_features 948 }, 949 { 950 "read_remote_version_information <connection_handle>", 951 "\nThis command will obtain the values for the version information for the\n" \ 952 "remote Bluetooth unit identified by the connection handle parameter. The\n" \ 953 "connection handle must be a connection handle for an ACL connection.\n\n" \ 954 "\t<connection_handle> - dddd; connection handle", 955 &hci_read_remote_version_information 956 }, 957 { 958 "read_clock_offset <connection_handle>", 959 "\nThis command allows the Host to read the clock offset from the remote unit.\n" \ 960 "\t<connection_handle> - dddd; connection handle", 961 &hci_read_clock_offset 962 }, 963 { 964 NULL, 965 }}; 966 967