hccontrol.c revision 158834
1107120Sjulian/* 2107120Sjulian * hccontrol.c 3107120Sjulian * 4107120Sjulian * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5107120Sjulian * All rights reserved. 6107120Sjulian * 7107120Sjulian * Redistribution and use in source and binary forms, with or without 8107120Sjulian * modification, are permitted provided that the following conditions 9107120Sjulian * are met: 10107120Sjulian * 1. Redistributions of source code must retain the above copyright 11107120Sjulian * notice, this list of conditions and the following disclaimer. 12107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright 13107120Sjulian * notice, this list of conditions and the following disclaimer in the 14107120Sjulian * documentation and/or other materials provided with the distribution. 15107120Sjulian * 16107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26107120Sjulian * SUCH DAMAGE. 27107120Sjulian * 28121054Semax * $Id: hccontrol.c,v 1.5 2003/09/05 00:38:24 max Exp $ 29107120Sjulian * $FreeBSD: head/usr.sbin/bluetooth/hccontrol/hccontrol.c 158834 2006-05-22 17:58:09Z markus $ 30107120Sjulian */ 31107120Sjulian 32121054Semax#include <bluetooth.h> 33158834Smarkus#include <sys/ioctl.h> 34107120Sjulian#include <sys/sysctl.h> 35107120Sjulian#include <assert.h> 36107120Sjulian#include <err.h> 37107120Sjulian#include <errno.h> 38158834Smarkus#include <netgraph/ng_message.h> 39107120Sjulian#include <stdio.h> 40107120Sjulian#include <stdlib.h> 41107120Sjulian#include <string.h> 42107120Sjulian#include <unistd.h> 43107120Sjulian#include "hccontrol.h" 44107120Sjulian 45107120Sjulian/* Prototypes */ 46107120Sjulianstatic int do_hci_command (char const *, int, char **); 47107120Sjulianstatic struct hci_command * find_hci_command (char const *, struct hci_command *); 48158834Smarkusstatic int find_hci_nodes (struct nodeinfo **); 49107120Sjulianstatic void print_hci_command (struct hci_command *); 50107120Sjulianstatic void usage (void); 51107120Sjulian 52107120Sjulian/* Globals */ 53107120Sjulianint verbose = 0; 54107120Sjulianint timeout; 55121054Semaxint numeric_bdaddr = 0; 56107120Sjulian 57107120Sjulian/* Main */ 58107120Sjulianint 59107120Sjulianmain(int argc, char *argv[]) 60107120Sjulian{ 61107120Sjulian char *node = NULL; 62107120Sjulian int n; 63107120Sjulian 64107120Sjulian /* Process command line arguments */ 65121054Semax while ((n = getopt(argc, argv, "n:Nvh")) != -1) { 66107120Sjulian switch (n) { 67107120Sjulian case 'n': 68107120Sjulian node = optarg; 69107120Sjulian break; 70107120Sjulian 71121054Semax case 'N': 72121054Semax numeric_bdaddr = 1; 73121054Semax break; 74121054Semax 75107120Sjulian case 'v': 76107120Sjulian verbose = 1; 77107120Sjulian break; 78107120Sjulian 79114879Sjulian case 'h': 80107120Sjulian default: 81107120Sjulian usage(); 82107120Sjulian } 83107120Sjulian } 84107120Sjulian 85107120Sjulian argc -= optind; 86107120Sjulian argv += optind; 87107120Sjulian 88107120Sjulian if (*argv == NULL) 89107120Sjulian usage(); 90107120Sjulian 91107120Sjulian n = do_hci_command(node, argc, argv); 92107120Sjulian 93107120Sjulian return (n); 94107120Sjulian} /* main */ 95107120Sjulian 96107120Sjulian/* Create socket and bind it */ 97107120Sjulianstatic int 98107120Sjuliansocket_open(char const *node) 99107120Sjulian{ 100158834Smarkus struct sockaddr_hci addr; 101158834Smarkus struct ng_btsocket_hci_raw_filter filter; 102158834Smarkus int s, mib[4]; 103158834Smarkus size_t size; 104158834Smarkus struct nodeinfo *nodes; 105107120Sjulian 106158834Smarkus if (find_hci_nodes(&nodes) == 0) 107158834Smarkus err(7, "Could not find HCI nodes"); 108107120Sjulian 109158834Smarkus if (node == NULL) { 110158834Smarkus node = strdup(nodes[0].name); 111158834Smarkus fprintf(stdout, "Using HCI node: %s\n", node); 112158834Smarkus } 113158834Smarkus 114158834Smarkus free(nodes); 115158834Smarkus 116107120Sjulian s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); 117107120Sjulian if (s < 0) 118107120Sjulian err(1, "Could not create socket"); 119107120Sjulian 120107120Sjulian memset(&addr, 0, sizeof(addr)); 121107120Sjulian addr.hci_len = sizeof(addr); 122107120Sjulian addr.hci_family = AF_BLUETOOTH; 123107120Sjulian strncpy(addr.hci_node, node, sizeof(addr.hci_node)); 124107120Sjulian if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) 125107120Sjulian err(2, "Could not bind socket, node=%s", node); 126107120Sjulian 127107120Sjulian if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) 128107120Sjulian err(3, "Could not connect socket, node=%s", node); 129107120Sjulian 130107120Sjulian memset(&filter, 0, sizeof(filter)); 131107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1); 132107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1); 133107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_COMPL - 1); 134107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_RESULT - 1); 135107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_CON_COMPL - 1); 136107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_DISCON_COMPL - 1); 137107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL - 1); 138107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL - 1); 139107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL - 1); 140107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_RETURN_LINK_KEYS - 1); 141107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL - 1); 142107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_CON_PKT_TYPE_CHANGED - 1); 143107120Sjulian bit_set(filter.event_mask, NG_HCI_EVENT_ROLE_CHANGE - 1); 144107120Sjulian 145107120Sjulian if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER, 146107120Sjulian (void * const) &filter, sizeof(filter)) < 0) 147107120Sjulian err(4, "Could not setsockopt()"); 148107120Sjulian 149107120Sjulian size = (sizeof(mib)/sizeof(mib[0])); 150107120Sjulian if (sysctlnametomib("net.bluetooth.hci.command_timeout",mib,&size) < 0) 151107120Sjulian err(5, "Could not sysctlnametomib()"); 152107120Sjulian 153107120Sjulian if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), 154107120Sjulian (void *) &timeout, &size, NULL, 0) < 0) 155107120Sjulian err(6, "Could not sysctl()"); 156107120Sjulian 157107120Sjulian timeout ++; 158107120Sjulian 159107120Sjulian return (s); 160107120Sjulian} /* socket_open */ 161107120Sjulian 162107120Sjulian/* Execute commands */ 163107120Sjulianstatic int 164107120Sjuliando_hci_command(char const *node, int argc, char **argv) 165107120Sjulian{ 166107120Sjulian char *cmd = argv[0]; 167107120Sjulian struct hci_command *c = NULL; 168107120Sjulian int s, e, help; 169107120Sjulian 170107120Sjulian help = 0; 171107120Sjulian if (strcasecmp(cmd, "help") == 0) { 172107120Sjulian argc --; 173107120Sjulian argv ++; 174107120Sjulian 175107120Sjulian if (argc <= 0) { 176107120Sjulian fprintf(stdout, "Supported commands:\n"); 177107120Sjulian print_hci_command(link_control_commands); 178107120Sjulian print_hci_command(link_policy_commands); 179107120Sjulian print_hci_command(host_controller_baseband_commands); 180107120Sjulian print_hci_command(info_commands); 181107120Sjulian print_hci_command(status_commands); 182107120Sjulian print_hci_command(node_commands); 183107120Sjulian fprintf(stdout, "\nFor more information use " \ 184107120Sjulian "'help command'\n"); 185107120Sjulian 186107120Sjulian return (OK); 187107120Sjulian } 188107120Sjulian 189107120Sjulian help = 1; 190107120Sjulian cmd = argv[0]; 191107120Sjulian } 192107120Sjulian 193107120Sjulian c = find_hci_command(cmd, link_control_commands); 194107120Sjulian if (c != NULL) 195107120Sjulian goto execute; 196107120Sjulian 197107120Sjulian c = find_hci_command(cmd, link_policy_commands); 198107120Sjulian if (c != NULL) 199107120Sjulian goto execute; 200107120Sjulian 201107120Sjulian c = find_hci_command(cmd, host_controller_baseband_commands); 202107120Sjulian if (c != NULL) 203107120Sjulian goto execute; 204107120Sjulian 205107120Sjulian c = find_hci_command(cmd, info_commands); 206107120Sjulian if (c != NULL) 207107120Sjulian goto execute; 208107120Sjulian 209107120Sjulian c = find_hci_command(cmd, status_commands); 210107120Sjulian if (c != NULL) 211107120Sjulian goto execute; 212107120Sjulian 213107120Sjulian c = find_hci_command(cmd, node_commands); 214107120Sjulian if (c == NULL) { 215107120Sjulian fprintf(stdout, "Unknown command: \"%s\"\n", cmd); 216107120Sjulian return (ERROR); 217107120Sjulian } 218107120Sjulianexecute: 219107120Sjulian if (!help) { 220107120Sjulian s = socket_open(node); 221107120Sjulian e = (c->handler)(s, -- argc, ++ argv); 222107120Sjulian close(s); 223107120Sjulian } else 224107120Sjulian e = USAGE; 225107120Sjulian 226107120Sjulian switch (e) { 227107120Sjulian case OK: 228107120Sjulian case FAILED: 229107120Sjulian break; 230107120Sjulian 231107120Sjulian case ERROR: 232107120Sjulian fprintf(stdout, "Could not execute command \"%s\". %s\n", 233107120Sjulian cmd, strerror(errno)); 234107120Sjulian break; 235107120Sjulian 236107120Sjulian case USAGE: 237107120Sjulian fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description); 238107120Sjulian break; 239107120Sjulian 240107120Sjulian default: assert(0); break; 241107120Sjulian } 242107120Sjulian 243107120Sjulian 244107120Sjulian return (e); 245107120Sjulian} /* do_hci_command */ 246107120Sjulian 247107120Sjulian/* Try to find command in specified category */ 248107120Sjulianstatic struct hci_command * 249107120Sjulianfind_hci_command(char const *command, struct hci_command *category) 250107120Sjulian{ 251107120Sjulian struct hci_command *c = NULL; 252107120Sjulian 253107120Sjulian for (c = category; c->command != NULL; c++) { 254107120Sjulian char *c_end = strchr(c->command, ' '); 255107120Sjulian 256107120Sjulian if (c_end != NULL) { 257107120Sjulian int len = c_end - c->command; 258107120Sjulian 259107120Sjulian if (strncasecmp(command, c->command, len) == 0) 260107120Sjulian return (c); 261107120Sjulian } else if (strcasecmp(command, c->command) == 0) 262107120Sjulian return (c); 263107120Sjulian } 264107120Sjulian 265107120Sjulian return (NULL); 266107120Sjulian} /* find_hci_command */ 267107120Sjulian 268158834Smarkus/* Find all HCI nodes */ 269158834Smarkusstatic int 270158834Smarkusfind_hci_nodes(struct nodeinfo** nodes) 271158834Smarkus{ 272158834Smarkus struct ng_btsocket_hci_raw_node_list_names r; 273158834Smarkus struct sockaddr_hci addr; 274158834Smarkus int s; 275158834Smarkus const char * node = "ubt0hci"; 276158834Smarkus 277158834Smarkus r.num_names = MAX_NODE_NUM; 278158834Smarkus r.names = (struct nodeinfo*)calloc(MAX_NODE_NUM, sizeof(struct nodeinfo)); 279158834Smarkus if (r.names == NULL) 280158834Smarkus err(8, "Could not allocate memory"); 281158834Smarkus 282158834Smarkus s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); 283158834Smarkus if (s < 0) 284158834Smarkus err(9, "Could not create socket"); 285158834Smarkus 286158834Smarkus memset(&addr, 0, sizeof(addr)); 287158834Smarkus addr.hci_len = sizeof(addr); 288158834Smarkus addr.hci_family = AF_BLUETOOTH; 289158834Smarkus strncpy(addr.hci_node, node, sizeof(addr.hci_node)); 290158834Smarkus if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) 291158834Smarkus err(10, "Could not bind socket"); 292158834Smarkus 293158834Smarkus if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0) 294158834Smarkus err(11, "Could not get list of HCI nodes"); 295158834Smarkus 296158834Smarkus close(s); 297158834Smarkus 298158834Smarkus *nodes = r.names; 299158834Smarkus 300158834Smarkus return (r.num_names); 301158834Smarkus} /* find_hci_nodes */ 302158834Smarkus 303121054Semax/* Print commands in specified category */ 304107120Sjulianstatic void 305107120Sjulianprint_hci_command(struct hci_command *category) 306107120Sjulian{ 307107120Sjulian struct hci_command *c = NULL; 308107120Sjulian 309107120Sjulian for (c = category; c->command != NULL; c++) 310107120Sjulian fprintf(stdout, "\t%s\n", c->command); 311107120Sjulian} /* print_hci_command */ 312107120Sjulian 313107120Sjulian/* Usage */ 314107120Sjulianstatic void 315107120Sjulianusage(void) 316107120Sjulian{ 317158834Smarkus fprintf(stdout, "Usage: hccontrol [-hN] [-n HCI_node_name] cmd [p1] [..]\n"); 318107120Sjulian exit(255); 319107120Sjulian} /* usage */ 320107120Sjulian 321