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