1baeef614SMaksim Yevmenkin /* 2baeef614SMaksim Yevmenkin * hci.c 3baeef614SMaksim Yevmenkin */ 4baeef614SMaksim Yevmenkin 5baeef614SMaksim Yevmenkin /*- 6baeef614SMaksim Yevmenkin * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7baeef614SMaksim Yevmenkin * All rights reserved. 8baeef614SMaksim Yevmenkin * 9baeef614SMaksim Yevmenkin * Redistribution and use in source and binary forms, with or without 10baeef614SMaksim Yevmenkin * modification, are permitted provided that the following conditions 11baeef614SMaksim Yevmenkin * are met: 12baeef614SMaksim Yevmenkin * 1. Redistributions of source code must retain the above copyright 13baeef614SMaksim Yevmenkin * notice, this list of conditions and the following disclaimer. 14baeef614SMaksim Yevmenkin * 2. Redistributions in binary form must reproduce the above copyright 15baeef614SMaksim Yevmenkin * notice, this list of conditions and the following disclaimer in the 16baeef614SMaksim Yevmenkin * documentation and/or other materials provided with the distribution. 17baeef614SMaksim Yevmenkin * 18baeef614SMaksim Yevmenkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19baeef614SMaksim Yevmenkin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20baeef614SMaksim Yevmenkin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21baeef614SMaksim Yevmenkin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22baeef614SMaksim Yevmenkin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23baeef614SMaksim Yevmenkin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24baeef614SMaksim Yevmenkin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25baeef614SMaksim Yevmenkin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26baeef614SMaksim Yevmenkin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27baeef614SMaksim Yevmenkin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28baeef614SMaksim Yevmenkin * SUCH DAMAGE. 29baeef614SMaksim Yevmenkin * 30baeef614SMaksim Yevmenkin * $FreeBSD$ 31baeef614SMaksim Yevmenkin */ 32baeef614SMaksim Yevmenkin 33baeef614SMaksim Yevmenkin #include <bluetooth.h> 34baeef614SMaksim Yevmenkin #include <stdio.h> 35baeef614SMaksim Yevmenkin #include <stdlib.h> 36baeef614SMaksim Yevmenkin #include <string.h> 37baeef614SMaksim Yevmenkin #include <unistd.h> 38baeef614SMaksim Yevmenkin 39baeef614SMaksim Yevmenkin static char * bt_dev2node (char const *devname, char *nodename, int nnlen); 40baeef614SMaksim Yevmenkin 41baeef614SMaksim Yevmenkin int 42baeef614SMaksim Yevmenkin bt_devinfo(struct bt_devinfo *di) 43baeef614SMaksim Yevmenkin { 44baeef614SMaksim Yevmenkin union { 45baeef614SMaksim Yevmenkin struct ng_btsocket_hci_raw_node_state r0; 46baeef614SMaksim Yevmenkin struct ng_btsocket_hci_raw_node_bdaddr r1; 47baeef614SMaksim Yevmenkin struct ng_btsocket_hci_raw_node_features r2; 48baeef614SMaksim Yevmenkin struct ng_btsocket_hci_raw_node_buffer r3; 49baeef614SMaksim Yevmenkin struct ng_btsocket_hci_raw_node_stat r4; 50baeef614SMaksim Yevmenkin struct ng_btsocket_hci_raw_node_link_policy_mask r5; 51baeef614SMaksim Yevmenkin struct ng_btsocket_hci_raw_node_packet_mask r6; 52baeef614SMaksim Yevmenkin struct ng_btsocket_hci_raw_node_role_switch r7; 53baeef614SMaksim Yevmenkin struct ng_btsocket_hci_raw_node_debug r8; 54baeef614SMaksim Yevmenkin } rp; 55baeef614SMaksim Yevmenkin struct sockaddr_hci ha; 56baeef614SMaksim Yevmenkin int s, rval; 57baeef614SMaksim Yevmenkin 58baeef614SMaksim Yevmenkin if (di == NULL) { 59baeef614SMaksim Yevmenkin errno = EINVAL; 60baeef614SMaksim Yevmenkin return (-1); 61baeef614SMaksim Yevmenkin } 62baeef614SMaksim Yevmenkin 63baeef614SMaksim Yevmenkin memset(&ha, 0, sizeof(ha)); 64baeef614SMaksim Yevmenkin ha.hci_len = sizeof(ha); 65baeef614SMaksim Yevmenkin ha.hci_family = AF_BLUETOOTH; 66baeef614SMaksim Yevmenkin 67baeef614SMaksim Yevmenkin if (bt_aton(di->devname, &rp.r1.bdaddr)) { 68baeef614SMaksim Yevmenkin if (!bt_devname(ha.hci_node, &rp.r1.bdaddr)) 69baeef614SMaksim Yevmenkin return (-1); 70baeef614SMaksim Yevmenkin } else if (bt_dev2node(di->devname, ha.hci_node, 71baeef614SMaksim Yevmenkin sizeof(ha.hci_node)) == NULL) { 72baeef614SMaksim Yevmenkin errno = ENXIO; 73baeef614SMaksim Yevmenkin return (-1); 74baeef614SMaksim Yevmenkin } 75baeef614SMaksim Yevmenkin 76baeef614SMaksim Yevmenkin s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); 77baeef614SMaksim Yevmenkin if (s < 0) 78baeef614SMaksim Yevmenkin return (-1); 79baeef614SMaksim Yevmenkin 80baeef614SMaksim Yevmenkin rval = -1; 81baeef614SMaksim Yevmenkin 82baeef614SMaksim Yevmenkin if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || 83baeef614SMaksim Yevmenkin connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0) 84baeef614SMaksim Yevmenkin goto bad; 85baeef614SMaksim Yevmenkin strlcpy(di->devname, ha.hci_node, sizeof(di->devname)); 86baeef614SMaksim Yevmenkin 87baeef614SMaksim Yevmenkin if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &rp.r0, sizeof(rp.r0)) < 0) 88baeef614SMaksim Yevmenkin goto bad; 89baeef614SMaksim Yevmenkin di->state = rp.r0.state; 90baeef614SMaksim Yevmenkin 91baeef614SMaksim Yevmenkin if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &rp.r1, sizeof(rp.r1)) < 0) 92baeef614SMaksim Yevmenkin goto bad; 93baeef614SMaksim Yevmenkin bdaddr_copy(&di->bdaddr, &rp.r1.bdaddr); 94baeef614SMaksim Yevmenkin 95baeef614SMaksim Yevmenkin if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &rp.r2, sizeof(rp.r2)) < 0) 96baeef614SMaksim Yevmenkin goto bad; 97baeef614SMaksim Yevmenkin memcpy(di->features, rp.r2.features, sizeof(di->features)); 98baeef614SMaksim Yevmenkin 99baeef614SMaksim Yevmenkin if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &rp.r3, sizeof(rp.r3)) < 0) 100baeef614SMaksim Yevmenkin goto bad; 101baeef614SMaksim Yevmenkin di->cmd_free = rp.r3.buffer.cmd_free; 102baeef614SMaksim Yevmenkin di->sco_size = rp.r3.buffer.sco_size; 103baeef614SMaksim Yevmenkin di->sco_pkts = rp.r3.buffer.sco_pkts; 104baeef614SMaksim Yevmenkin di->sco_free = rp.r3.buffer.sco_free; 105baeef614SMaksim Yevmenkin di->acl_size = rp.r3.buffer.acl_size; 106baeef614SMaksim Yevmenkin di->acl_pkts = rp.r3.buffer.acl_pkts; 107baeef614SMaksim Yevmenkin di->acl_free = rp.r3.buffer.acl_free; 108baeef614SMaksim Yevmenkin 109baeef614SMaksim Yevmenkin if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &rp.r4, sizeof(rp.r4)) < 0) 110baeef614SMaksim Yevmenkin goto bad; 111baeef614SMaksim Yevmenkin di->cmd_sent = rp.r4.stat.cmd_sent; 112baeef614SMaksim Yevmenkin di->evnt_recv = rp.r4.stat.evnt_recv; 113baeef614SMaksim Yevmenkin di->acl_recv = rp.r4.stat.acl_recv; 114baeef614SMaksim Yevmenkin di->acl_sent = rp.r4.stat.acl_sent; 115baeef614SMaksim Yevmenkin di->sco_recv = rp.r4.stat.sco_recv; 116baeef614SMaksim Yevmenkin di->sco_sent = rp.r4.stat.sco_sent; 117baeef614SMaksim Yevmenkin di->bytes_recv = rp.r4.stat.bytes_recv; 118baeef614SMaksim Yevmenkin di->bytes_sent = rp.r4.stat.bytes_sent; 119baeef614SMaksim Yevmenkin 120baeef614SMaksim Yevmenkin if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, 121baeef614SMaksim Yevmenkin &rp.r5, sizeof(rp.r5)) < 0) 122baeef614SMaksim Yevmenkin goto bad; 123baeef614SMaksim Yevmenkin di->link_policy_info = rp.r5.policy_mask; 124baeef614SMaksim Yevmenkin 125baeef614SMaksim Yevmenkin if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, 126baeef614SMaksim Yevmenkin &rp.r6, sizeof(rp.r6)) < 0) 127baeef614SMaksim Yevmenkin goto bad; 128baeef614SMaksim Yevmenkin di->packet_type_info = rp.r6.packet_mask; 129baeef614SMaksim Yevmenkin 130baeef614SMaksim Yevmenkin if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH, 131baeef614SMaksim Yevmenkin &rp.r7, sizeof(rp.r7)) < 0) 132baeef614SMaksim Yevmenkin goto bad; 133baeef614SMaksim Yevmenkin di->role_switch_info = rp.r7.role_switch; 134baeef614SMaksim Yevmenkin 135baeef614SMaksim Yevmenkin if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &rp.r8, sizeof(rp.r8)) < 0) 136baeef614SMaksim Yevmenkin goto bad; 137baeef614SMaksim Yevmenkin di->debug = rp.r8.debug; 138baeef614SMaksim Yevmenkin 139baeef614SMaksim Yevmenkin rval = 0; 140baeef614SMaksim Yevmenkin bad: 141baeef614SMaksim Yevmenkin close(s); 142baeef614SMaksim Yevmenkin 143baeef614SMaksim Yevmenkin return (rval); 144baeef614SMaksim Yevmenkin } 145baeef614SMaksim Yevmenkin 146baeef614SMaksim Yevmenkin int 147baeef614SMaksim Yevmenkin bt_devenum(bt_devenum_cb_t cb, void *arg) 148baeef614SMaksim Yevmenkin { 149baeef614SMaksim Yevmenkin struct ng_btsocket_hci_raw_node_list_names rp; 150baeef614SMaksim Yevmenkin struct bt_devinfo di; 151baeef614SMaksim Yevmenkin struct sockaddr_hci ha; 152baeef614SMaksim Yevmenkin int s, i, count; 153baeef614SMaksim Yevmenkin 154baeef614SMaksim Yevmenkin rp.num_names = HCI_DEVMAX; 155baeef614SMaksim Yevmenkin rp.names = (struct nodeinfo *) calloc(rp.num_names, 156baeef614SMaksim Yevmenkin sizeof(struct nodeinfo)); 157baeef614SMaksim Yevmenkin if (rp.names == NULL) { 158baeef614SMaksim Yevmenkin errno = ENOMEM; 159baeef614SMaksim Yevmenkin return (-1); 160baeef614SMaksim Yevmenkin } 161baeef614SMaksim Yevmenkin 162baeef614SMaksim Yevmenkin memset(&ha, 0, sizeof(ha)); 163baeef614SMaksim Yevmenkin ha.hci_len = sizeof(ha); 164baeef614SMaksim Yevmenkin ha.hci_family = AF_BLUETOOTH; 165baeef614SMaksim Yevmenkin ha.hci_node[0] = 'x'; 166baeef614SMaksim Yevmenkin 167baeef614SMaksim Yevmenkin s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); 168baeef614SMaksim Yevmenkin if (s < 0) { 169baeef614SMaksim Yevmenkin free(rp.names); 170baeef614SMaksim Yevmenkin 171baeef614SMaksim Yevmenkin return (-1); 172baeef614SMaksim Yevmenkin } 173baeef614SMaksim Yevmenkin 174baeef614SMaksim Yevmenkin if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || 175baeef614SMaksim Yevmenkin connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || 176baeef614SMaksim Yevmenkin ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &rp, sizeof(rp)) < 0) { 177baeef614SMaksim Yevmenkin close(s); 178baeef614SMaksim Yevmenkin free(rp.names); 179baeef614SMaksim Yevmenkin 180baeef614SMaksim Yevmenkin return (-1); 181baeef614SMaksim Yevmenkin } 182baeef614SMaksim Yevmenkin 183baeef614SMaksim Yevmenkin for (count = 0, i = 0; i < rp.num_names; i ++) { 184baeef614SMaksim Yevmenkin strlcpy(di.devname, rp.names[i].name, sizeof(di.devname)); 185baeef614SMaksim Yevmenkin if (bt_devinfo(&di) < 0) 186baeef614SMaksim Yevmenkin continue; 187baeef614SMaksim Yevmenkin 188baeef614SMaksim Yevmenkin count ++; 189baeef614SMaksim Yevmenkin 190baeef614SMaksim Yevmenkin if (cb == NULL) 191baeef614SMaksim Yevmenkin continue; 192baeef614SMaksim Yevmenkin 193baeef614SMaksim Yevmenkin strlcpy(ha.hci_node, rp.names[i].name, sizeof(ha.hci_node)); 194baeef614SMaksim Yevmenkin if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || 195baeef614SMaksim Yevmenkin connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0) 196baeef614SMaksim Yevmenkin continue; 197baeef614SMaksim Yevmenkin 198baeef614SMaksim Yevmenkin if ((*cb)(s, &di, arg) > 0) 199baeef614SMaksim Yevmenkin break; 200baeef614SMaksim Yevmenkin } 201baeef614SMaksim Yevmenkin 202baeef614SMaksim Yevmenkin close (s); 203baeef614SMaksim Yevmenkin free(rp.names); 204baeef614SMaksim Yevmenkin 205baeef614SMaksim Yevmenkin return (count); 206baeef614SMaksim Yevmenkin } 207baeef614SMaksim Yevmenkin 208baeef614SMaksim Yevmenkin static char * 209baeef614SMaksim Yevmenkin bt_dev2node(char const *devname, char *nodename, int nnlen) 210baeef614SMaksim Yevmenkin { 211baeef614SMaksim Yevmenkin static char const * bt_dev_prefix[] = { 212baeef614SMaksim Yevmenkin "btccc", /* 3Com Bluetooth PC-CARD */ 213baeef614SMaksim Yevmenkin "h4", /* UART/serial Bluetooth devices */ 214baeef614SMaksim Yevmenkin "ubt", /* Bluetooth USB devices */ 215baeef614SMaksim Yevmenkin NULL /* should be last */ 216baeef614SMaksim Yevmenkin }; 217baeef614SMaksim Yevmenkin 218baeef614SMaksim Yevmenkin static char _nodename[HCI_DEVNAME_SIZE]; 219baeef614SMaksim Yevmenkin char const **p; 220baeef614SMaksim Yevmenkin char *ep; 221baeef614SMaksim Yevmenkin int plen, unit; 222baeef614SMaksim Yevmenkin 223baeef614SMaksim Yevmenkin if (nodename == NULL) { 224baeef614SMaksim Yevmenkin nodename = _nodename; 225baeef614SMaksim Yevmenkin nnlen = HCI_DEVNAME_SIZE; 226baeef614SMaksim Yevmenkin } 227baeef614SMaksim Yevmenkin 228baeef614SMaksim Yevmenkin for (p = bt_dev_prefix; *p != NULL; p ++) { 229baeef614SMaksim Yevmenkin plen = strlen(*p); 230baeef614SMaksim Yevmenkin if (strncmp(devname, *p, plen) != 0) 231baeef614SMaksim Yevmenkin continue; 232baeef614SMaksim Yevmenkin 233baeef614SMaksim Yevmenkin unit = strtoul(devname + plen, &ep, 10); 234baeef614SMaksim Yevmenkin if (*ep != '\0' && 235baeef614SMaksim Yevmenkin strcmp(ep, "hci") != 0 && 236baeef614SMaksim Yevmenkin strcmp(ep, "l2cap") != 0) 237baeef614SMaksim Yevmenkin return (NULL); /* can't make sense of device name */ 238baeef614SMaksim Yevmenkin 239baeef614SMaksim Yevmenkin snprintf(nodename, nnlen, "%s%uhci", *p, unit); 240baeef614SMaksim Yevmenkin 241baeef614SMaksim Yevmenkin return (nodename); 242baeef614SMaksim Yevmenkin } 243baeef614SMaksim Yevmenkin 244baeef614SMaksim Yevmenkin return (NULL); 245baeef614SMaksim Yevmenkin } 246baeef614SMaksim Yevmenkin 247