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