1 /*- 2 * node.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: node.c,v 1.6 2003/07/22 21:14:02 max Exp $ 31 * $FreeBSD$ 32 */ 33 34 #include <sys/ioctl.h> 35 #define L2CAP_SOCKET_CHECKED 36 #include <bluetooth.h> 37 #include <errno.h> 38 #include <netgraph/ng_message.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 #include <uuid.h> 44 #include "hccontrol.h" 45 46 /* Send Read_Node_State command to the node */ 47 static int 48 hci_read_node_state(int s, int argc, char **argv) 49 { 50 struct ng_btsocket_hci_raw_node_state r; 51 52 memset(&r, 0, sizeof(r)); 53 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &r, sizeof(r)) < 0) 54 return (ERROR); 55 56 fprintf(stdout, "State: %#x\n", r.state); 57 58 return (OK); 59 } /* hci_read_node_state */ 60 61 /* Send Intitialize command to the node */ 62 static int 63 hci_node_initialize(int s, int argc, char **argv) 64 { 65 if (ioctl(s, SIOC_HCI_RAW_NODE_INIT) < 0) 66 return (ERROR); 67 68 return (OK); 69 } /* hci_node_initialize */ 70 71 /* Send Read_Debug_Level command to the node */ 72 static int 73 hci_read_debug_level(int s, int argc, char **argv) 74 { 75 struct ng_btsocket_hci_raw_node_debug r; 76 77 memset(&r, 0, sizeof(r)); 78 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &r, sizeof(r)) < 0) 79 return (ERROR); 80 81 fprintf(stdout, "Debug level: %d\n", r.debug); 82 83 return (OK); 84 } /* hci_read_debug_level */ 85 86 /* Send Write_Debug_Level command to the node */ 87 static int 88 hci_write_debug_level(int s, int argc, char **argv) 89 { 90 struct ng_btsocket_hci_raw_node_debug r; 91 92 memset(&r, 0, sizeof(r)); 93 switch (argc) { 94 case 1: 95 r.debug = atoi(argv[0]); 96 break; 97 98 default: 99 return (USAGE); 100 } 101 102 if (ioctl(s, SIOC_HCI_RAW_NODE_SET_DEBUG, &r, sizeof(r)) < 0) 103 return (ERROR); 104 105 return (OK); 106 } /* hci_write_debug_level */ 107 108 /* Send Read_Node_Buffer_Size command to the node */ 109 static int 110 hci_read_node_buffer_size(int s, int argc, char **argv) 111 { 112 struct ng_btsocket_hci_raw_node_buffer r; 113 114 memset(&r, 0, sizeof(r)); 115 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &r, sizeof(r)) < 0) 116 return (ERROR); 117 118 fprintf(stdout, "Number of free command buffers: %d\n", 119 r.buffer.cmd_free); 120 fprintf(stdout, "Max. ACL packet size: %d\n", 121 r.buffer.acl_size); 122 fprintf(stdout, "Numbef of free ACL buffers: %d\n", 123 r.buffer.acl_free); 124 fprintf(stdout, "Total number of ACL buffers: %d\n", 125 r.buffer.acl_pkts); 126 fprintf(stdout, "Max. SCO packet size: %d\n", 127 r.buffer.sco_size); 128 fprintf(stdout, "Numbef of free SCO buffers: %d\n", 129 r.buffer.sco_free); 130 fprintf(stdout, "Total number of SCO buffers: %d\n", 131 r.buffer.sco_pkts); 132 133 return (OK); 134 } /* hci_read_node_buffer_size */ 135 136 /* Send Read_Node_BD_ADDR command to the node */ 137 static int 138 hci_read_node_bd_addr(int s, int argc, char **argv) 139 { 140 struct ng_btsocket_hci_raw_node_bdaddr r; 141 142 memset(&r, 0, sizeof(r)); 143 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &r, sizeof(r)) < 0) 144 return (ERROR); 145 146 fprintf(stdout, "BD_ADDR: %s\n", bt_ntoa(&r.bdaddr, NULL)); 147 148 return (OK); 149 } /* hci_read_node_bd_addr */ 150 151 /* Send Read_Node_Features command to the node */ 152 static int 153 hci_read_node_features(int s, int argc, char **argv) 154 { 155 struct ng_btsocket_hci_raw_node_features r; 156 int n; 157 char buffer[2048]; 158 159 memset(&r, 0, sizeof(r)); 160 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &r, sizeof(r)) < 0) 161 return (ERROR); 162 163 fprintf(stdout, "Features: "); 164 for (n = 0; n < sizeof(r.features)/sizeof(r.features[0]); n++) 165 fprintf(stdout, "%#02x ", r.features[n]); 166 fprintf(stdout, "\n%s\n", hci_features2str(r.features, 167 buffer, sizeof(buffer))); 168 169 return (OK); 170 } /* hci_read_node_features */ 171 172 /* Send Read_Node_Stat command to the node */ 173 static int 174 hci_read_node_stat(int s, int argc, char **argv) 175 { 176 struct ng_btsocket_hci_raw_node_stat r; 177 178 memset(&r, 0, sizeof(r)); 179 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &r, sizeof(r)) < 0) 180 return (ERROR); 181 182 fprintf(stdout, "Commands sent: %d\n", r.stat.cmd_sent); 183 fprintf(stdout, "Events received: %d\n", r.stat.evnt_recv); 184 fprintf(stdout, "ACL packets received: %d\n", r.stat.acl_recv); 185 fprintf(stdout, "ACL packets sent: %d\n", r.stat.acl_sent); 186 fprintf(stdout, "SCO packets received: %d\n", r.stat.sco_recv); 187 fprintf(stdout, "SCO packets sent: %d\n", r.stat.sco_sent); 188 fprintf(stdout, "Bytes received: %d\n", r.stat.bytes_recv); 189 fprintf(stdout, "Bytes sent: %d\n", r.stat.bytes_sent); 190 191 return (OK); 192 } /* hci_read_node_stat */ 193 194 /* Send Reset_Node_Stat command to the node */ 195 static int 196 hci_reset_node_stat(int s, int argc, char **argv) 197 { 198 if (ioctl(s, SIOC_HCI_RAW_NODE_RESET_STAT) < 0) 199 return (ERROR); 200 201 return (OK); 202 } /* hci_reset_node_stat */ 203 204 /* Send Flush_Neighbor_Cache command to the node */ 205 static int 206 hci_flush_neighbor_cache(int s, int argc, char **argv) 207 { 208 if (ioctl(s, SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE) < 0) 209 return (ERROR); 210 211 return (OK); 212 } /* hci_flush_neighbor_cache */ 213 214 /* Send Read_Neighbor_Cache command to the node */ 215 static int 216 hci_read_neighbor_cache(int s, int argc, char **argv) 217 { 218 struct ng_btsocket_hci_raw_node_neighbor_cache r; 219 int n, error = OK; 220 const char *addrtype2str[] = {"B", "P", "R", "E"}; 221 222 memset(&r, 0, sizeof(r)); 223 r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM; 224 r.entries = calloc(NG_HCI_MAX_NEIGHBOR_NUM, 225 sizeof(ng_hci_node_neighbor_cache_entry_ep)); 226 if (r.entries == NULL) { 227 errno = ENOMEM; 228 return (ERROR); 229 } 230 231 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE, &r, 232 sizeof(r)) < 0) { 233 error = ERROR; 234 goto out; 235 } 236 237 fprintf(stdout, 238 "T " \ 239 "BD_ADDR " \ 240 "Features " \ 241 "Clock offset " \ 242 "Page scan " \ 243 "Rep. scan\n"); 244 245 for (n = 0; n < r.num_entries; n++) { 246 uint8_t addrtype = r.entries[n].addrtype; 247 if(addrtype >= sizeof(addrtype2str)/sizeof(addrtype2str[0])) 248 addrtype = sizeof(addrtype2str)/sizeof(addrtype2str[0]) - 1; 249 fprintf(stdout, 250 "%1s %-17.17s " \ 251 "%02x %02x %02x %02x %02x %02x %02x %02x " \ 252 "%#12x " \ 253 "%#9x " \ 254 "%#9x\n", 255 addrtype2str[addrtype], 256 hci_bdaddr2str(&r.entries[n].bdaddr), 257 r.entries[n].features[0], r.entries[n].features[1], 258 r.entries[n].features[2], r.entries[n].features[3], 259 r.entries[n].features[4], r.entries[n].features[5], 260 r.entries[n].features[6], r.entries[n].features[7], 261 r.entries[n].clock_offset, r.entries[n].page_scan_mode, 262 r.entries[n].page_scan_rep_mode); 263 print_adv_data(r.entries[n].extinq_size, 264 r.entries[n].extinq_data); 265 fprintf(stdout,"\n"); 266 } 267 out: 268 free(r.entries); 269 270 return (error); 271 } /* hci_read_neightbor_cache */ 272 273 /* Send Read_Connection_List command to the node */ 274 static int 275 hci_read_connection_list(int s, int argc, char **argv) 276 { 277 struct ng_btsocket_hci_raw_con_list r; 278 int n, error = OK; 279 280 memset(&r, 0, sizeof(r)); 281 r.num_connections = NG_HCI_MAX_CON_NUM; 282 r.connections = calloc(NG_HCI_MAX_CON_NUM, sizeof(ng_hci_node_con_ep)); 283 if (r.connections == NULL) { 284 errno = ENOMEM; 285 return (ERROR); 286 } 287 288 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) { 289 error = ERROR; 290 goto out; 291 } 292 293 fprintf(stdout, 294 "Remote BD_ADDR " \ 295 "Handle " \ 296 "Type " \ 297 "Mode " \ 298 "Role " \ 299 "Encrypt " \ 300 "Pending " \ 301 "Queue " \ 302 "State\n"); 303 304 for (n = 0; n < r.num_connections; n++) { 305 fprintf(stdout, 306 "%-17.17s " \ 307 "%6d " \ 308 "%4.4s " \ 309 "%4d " \ 310 "%4.4s " \ 311 "%7.7s " \ 312 "%7d " \ 313 "%5d " \ 314 "%s\n", 315 hci_bdaddr2str(&r.connections[n].bdaddr), 316 r.connections[n].con_handle, 317 (r.connections[n].link_type == NG_HCI_LINK_ACL)? 318 "ACL" : "SCO", 319 r.connections[n].mode, 320 (r.connections[n].role == NG_HCI_ROLE_MASTER)? 321 "MAST" : "SLAV", 322 hci_encrypt2str(r.connections[n].encryption_mode, 1), 323 r.connections[n].pending, 324 r.connections[n].queue_len, 325 hci_con_state2str(r.connections[n].state)); 326 } 327 out: 328 free(r.connections); 329 330 return (error); 331 } /* hci_read_connection_list */ 332 333 /* Send Read_Node_Link_Policy_Settings_Mask command to the node */ 334 int 335 hci_read_node_link_policy_settings_mask(int s, int argc, char **argv) 336 { 337 struct ng_btsocket_hci_raw_node_link_policy_mask r; 338 339 memset(&r, 0, sizeof(r)); 340 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, &r, sizeof(r)) < 0) 341 return (ERROR); 342 343 fprintf(stdout, "Link Policy Settings mask: %#04x\n", r.policy_mask); 344 345 return (OK); 346 } /* hci_read_node_link_policy_settings_mask */ 347 348 /* Send Write_Node_Link_Policy_Settings_Mask command to the node */ 349 int 350 hci_write_node_link_policy_settings_mask(int s, int argc, char **argv) 351 { 352 struct ng_btsocket_hci_raw_node_link_policy_mask r; 353 int m; 354 355 memset(&r, 0, sizeof(r)); 356 357 switch (argc) { 358 case 1: 359 if (sscanf(argv[0], "%x", &m) != 1) 360 return (USAGE); 361 362 r.policy_mask = (m & 0xffff); 363 break; 364 365 default: 366 return (USAGE); 367 } 368 369 if (ioctl(s, SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK, &r, sizeof(r)) < 0) 370 return (ERROR); 371 372 return (OK); 373 } /* hci_write_node_link_policy_settings_mask */ 374 375 /* Send Read_Node_Packet_Mask command to the node */ 376 int 377 hci_read_node_packet_mask(int s, int argc, char **argv) 378 { 379 struct ng_btsocket_hci_raw_node_packet_mask r; 380 381 memset(&r, 0, sizeof(r)); 382 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, &r, sizeof(r)) < 0) 383 return (ERROR); 384 385 fprintf(stdout, "Packet mask: %#04x\n", r.packet_mask); 386 387 return (OK); 388 } /* hci_read_node_packet_mask */ 389 390 /* Send Write_Node_Packet_Mask command to the node */ 391 int 392 hci_write_node_packet_mask(int s, int argc, char **argv) 393 { 394 struct ng_btsocket_hci_raw_node_packet_mask r; 395 int m; 396 397 memset(&r, 0, sizeof(r)); 398 399 switch (argc) { 400 case 1: 401 if (sscanf(argv[0], "%x", &m) != 1) 402 return (USAGE); 403 404 r.packet_mask = (m & 0xffff); 405 break; 406 407 default: 408 return (USAGE); 409 } 410 411 if (ioctl(s, SIOC_HCI_RAW_NODE_SET_PACKET_MASK, &r, sizeof(r)) < 0) 412 return (ERROR); 413 414 return (OK); 415 } /* hci_write_node_packet_mask */ 416 417 /* Send Read_Node_Role_Switch command to the node */ 418 int 419 hci_read_node_role_switch(int s, int argc, char **argv) 420 { 421 struct ng_btsocket_hci_raw_node_role_switch r; 422 423 memset(&r, 0, sizeof(r)); 424 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH, &r, sizeof(r)) < 0) 425 return (ERROR); 426 427 fprintf(stdout, "Role switch: %d\n", r.role_switch); 428 429 return (OK); 430 } /* hci_read_node_role_switch */ 431 432 /* Send Write_Node_Role_Switch command to the node */ 433 int 434 hci_write_node_role_switch(int s, int argc, char **argv) 435 { 436 struct ng_btsocket_hci_raw_node_role_switch r; 437 int m; 438 439 memset(&r, 0, sizeof(r)); 440 441 switch (argc) { 442 case 1: 443 if (sscanf(argv[0], "%d", &m) != 1) 444 return (USAGE); 445 446 r.role_switch = m? 1 : 0; 447 break; 448 449 default: 450 return (USAGE); 451 } 452 453 if (ioctl(s, SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH, &r, sizeof(r)) < 0) 454 return (ERROR); 455 456 return (OK); 457 } /* hci_write_node_role_switch */ 458 459 /* Send Read_Node_List command to the node */ 460 int 461 hci_read_node_list(int s, int argc, char **argv) 462 { 463 struct ng_btsocket_hci_raw_node_list_names r; 464 int i; 465 466 r.num_names = MAX_NODE_NUM; 467 r.names = (struct nodeinfo*)calloc(MAX_NODE_NUM, sizeof(struct nodeinfo)); 468 if (r.names == NULL) 469 return (ERROR); 470 471 if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0) { 472 free(r.names); 473 return (ERROR); 474 } 475 476 fprintf(stdout, "Name ID Num hooks\n"); 477 for (i = 0; i < r.num_names; ++i) 478 fprintf(stdout, "%-15s %08x %9d\n", 479 r.names[i].name, r.names[i].id, r.names[i].hooks); 480 481 free(r.names); 482 483 return (OK); 484 } /* hci_read_node_list */ 485 486 struct hci_command node_commands[] = { 487 { 488 "read_node_state", 489 "Get the HCI node state", 490 &hci_read_node_state 491 }, 492 { 493 "initialize", 494 "Initialize the HCI node", 495 &hci_node_initialize 496 }, 497 { 498 "read_debug_level", 499 "Read the HCI node debug level", 500 &hci_read_debug_level 501 }, 502 { 503 "write_debug_level <level>", 504 "Write the HCI node debug level", 505 &hci_write_debug_level 506 }, 507 { 508 "read_node_buffer_size", 509 "Read the HCI node buffer information. This will return current state of the\n"\ 510 "HCI buffer for the HCI node", 511 &hci_read_node_buffer_size 512 }, 513 { 514 "read_node_bd_addr", 515 "Read the HCI node BD_ADDR. Returns device BD_ADDR as cached by the HCI node", 516 &hci_read_node_bd_addr 517 }, 518 { 519 "read_node_features", 520 "Read the HCI node features. This will return list of supported features as\n" \ 521 "cached by the HCI node", 522 &hci_read_node_features 523 }, 524 { 525 "read_node_stat", 526 "Read packets and bytes counters for the HCI node", 527 &hci_read_node_stat 528 }, 529 { 530 "reset_node_stat", 531 "Reset packets and bytes counters for the HCI node", 532 &hci_reset_node_stat 533 }, 534 { 535 "flush_neighbor_cache", 536 "Flush content of the HCI node neighbor cache", 537 &hci_flush_neighbor_cache 538 }, 539 { 540 "read_neighbor_cache", 541 "Read content of the HCI node neighbor cache", 542 &hci_read_neighbor_cache 543 }, 544 { 545 "read_connection_list", 546 "Read the baseband connection descriptors list for the HCI node", 547 &hci_read_connection_list 548 }, 549 { 550 "read_node_link_policy_settings_mask", 551 "Read the value of the Link Policy Settinngs mask for the HCI node", 552 &hci_read_node_link_policy_settings_mask 553 }, 554 { 555 "write_node_link_policy_settings_mask <policy_mask>", 556 "Write the value of the Link Policy Settings mask for the HCI node. By default\n" \ 557 "all supported Link Policy modes (as reported by the local device features) are\n"\ 558 "enabled. The particular Link Policy mode is enabled if local device supports\n"\ 559 "it and correspinding bit in the mask was set\n\n" \ 560 "\t<policy_mask> - xxxx; Link Policy mask\n" \ 561 "\t\t0x0000 - Disable All LM Modes\n" \ 562 "\t\t0x0001 - Enable Master Slave Switch\n" \ 563 "\t\t0x0002 - Enable Hold Mode\n" \ 564 "\t\t0x0004 - Enable Sniff Mode\n" \ 565 "\t\t0x0008 - Enable Park Mode\n", 566 &hci_write_node_link_policy_settings_mask 567 }, 568 { 569 "read_node_packet_mask", 570 "Read the value of the Packet mask for the HCI node", 571 &hci_read_node_packet_mask 572 }, 573 { 574 "write_node_packet_mask <packet_mask>", 575 "Write the value of the Packet mask for the HCI node. By default all supported\n" \ 576 "packet types (as reported by the local device features) are enabled. The\n" \ 577 "particular packet type is enabled if local device supports it and corresponding\n" \ 578 "bit in the mask was set\n\n" \ 579 "\t<packet_mask> - xxxx; packet type mask\n" \ 580 "" \ 581 "\t\tACL packets\n" \ 582 "\t\t-----------\n" \ 583 "\t\t0x0008 DM1\n" \ 584 "\t\t0x0010 DH1\n" \ 585 "\t\t0x0400 DM3\n" \ 586 "\t\t0x0800 DH3\n" \ 587 "\t\t0x4000 DM5\n" \ 588 "\t\t0x8000 DH5\n" \ 589 "\n" \ 590 "\t\tSCO packets\n" \ 591 "\t\t-----------\n" \ 592 "\t\t0x0020 HV1\n" \ 593 "\t\t0x0040 HV2\n" \ 594 "\t\t0x0080 HV3\n", 595 &hci_write_node_packet_mask 596 }, 597 { 598 "read_node_role_switch", 599 "Read the value of the Role Switch parameter for the HCI node", 600 &hci_read_node_role_switch 601 }, 602 { 603 "write_node_role_switch {0|1}", 604 "Write the value of the Role Switch parameter for the HCI node. By default,\n" \ 605 "if Role Switch is supported, local device will try to perform Role Switch\n" \ 606 "and become Master on incoming connection. Some devices do not support Role\n" \ 607 "Switch and thus incoming connections from such devices will fail. Setting\n" \ 608 "this parameter to zero will prevent Role Switch and thus accepting device\n" \ 609 "will remain Slave", 610 &hci_write_node_role_switch 611 }, 612 { 613 "read_node_list", 614 "Get a list of HCI nodes, their Netgraph IDs and connected hooks.", 615 &hci_read_node_list 616 }, 617 { 618 NULL, 619 }}; 620 621