link_control.c revision 361153
1/*- 2 * link_control.c 3 * 4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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: stable/11/usr.sbin/bluetooth/hccontrol/link_control.c 361153 2020-05-18 08:42:10Z hselasky $ 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 41static void hci_inquiry_response (int n, uint8_t **b); 42 43/* Send Inquiry command to the unit */ 44static int 45hci_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 105wait_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 */ 149static void 150hci_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 */ 171static int 172hci_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 */ 261again: 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 */ 292static int 293hci_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 */ 337again: 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 */ 366static int 367hci_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 */ 416again: 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 */ 447static int 448hci_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 */ 487again: 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 */ 517static int 518hci_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 */ 580again: 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 */ 608static int 609hci_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 */ 643again: 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 */ 677static int 678hci_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 */ 711again: 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 */ 749static int 750hci_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 */ 783again: 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 813struct 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{ 961NULL, 962}}; 963 964