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