hci.c revision 189462
1/* 2 * hci.c 3 */ 4 5/*- 6 * Copyright (c) 2009 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 * $FreeBSD: head/lib/libbluetooth/hci.c 189462 2009-03-06 23:30:07Z emax $ 31 */ 32 33#include <bluetooth.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include <unistd.h> 38 39static char * bt_dev2node (char const *devname, char *nodename, int nnlen); 40 41int 42bt_devinfo(struct bt_devinfo *di) 43{ 44 union { 45 struct ng_btsocket_hci_raw_node_state r0; 46 struct ng_btsocket_hci_raw_node_bdaddr r1; 47 struct ng_btsocket_hci_raw_node_features r2; 48 struct ng_btsocket_hci_raw_node_buffer r3; 49 struct ng_btsocket_hci_raw_node_stat r4; 50 struct ng_btsocket_hci_raw_node_link_policy_mask r5; 51 struct ng_btsocket_hci_raw_node_packet_mask r6; 52 struct ng_btsocket_hci_raw_node_role_switch r7; 53 struct ng_btsocket_hci_raw_node_debug r8; 54 } rp; 55 struct sockaddr_hci ha; 56 int s, rval; 57 58 if (di == NULL) { 59 errno = EINVAL; 60 return (-1); 61 } 62 63 memset(&ha, 0, sizeof(ha)); 64 ha.hci_len = sizeof(ha); 65 ha.hci_family = AF_BLUETOOTH; 66 67 if (bt_aton(di->devname, &rp.r1.bdaddr)) { 68 if (!bt_devname(ha.hci_node, &rp.r1.bdaddr)) 69 return (-1); 70 } else if (bt_dev2node(di->devname, ha.hci_node, 71 sizeof(ha.hci_node)) == NULL) { 72 errno = ENXIO; 73 return (-1); 74 } 75 76 s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); 77 if (s < 0) 78 return (-1); 79 80 rval = -1; 81 82 if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || 83 connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0) 84 goto bad; 85 strlcpy(di->devname, ha.hci_node, sizeof(di->devname)); 86 87 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &rp.r0, sizeof(rp.r0)) < 0) 88 goto bad; 89 di->state = rp.r0.state; 90 91 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &rp.r1, sizeof(rp.r1)) < 0) 92 goto bad; 93 bdaddr_copy(&di->bdaddr, &rp.r1.bdaddr); 94 95 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &rp.r2, sizeof(rp.r2)) < 0) 96 goto bad; 97 memcpy(di->features, rp.r2.features, sizeof(di->features)); 98 99 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &rp.r3, sizeof(rp.r3)) < 0) 100 goto bad; 101 di->cmd_free = rp.r3.buffer.cmd_free; 102 di->sco_size = rp.r3.buffer.sco_size; 103 di->sco_pkts = rp.r3.buffer.sco_pkts; 104 di->sco_free = rp.r3.buffer.sco_free; 105 di->acl_size = rp.r3.buffer.acl_size; 106 di->acl_pkts = rp.r3.buffer.acl_pkts; 107 di->acl_free = rp.r3.buffer.acl_free; 108 109 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &rp.r4, sizeof(rp.r4)) < 0) 110 goto bad; 111 di->cmd_sent = rp.r4.stat.cmd_sent; 112 di->evnt_recv = rp.r4.stat.evnt_recv; 113 di->acl_recv = rp.r4.stat.acl_recv; 114 di->acl_sent = rp.r4.stat.acl_sent; 115 di->sco_recv = rp.r4.stat.sco_recv; 116 di->sco_sent = rp.r4.stat.sco_sent; 117 di->bytes_recv = rp.r4.stat.bytes_recv; 118 di->bytes_sent = rp.r4.stat.bytes_sent; 119 120 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, 121 &rp.r5, sizeof(rp.r5)) < 0) 122 goto bad; 123 di->link_policy_info = rp.r5.policy_mask; 124 125 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, 126 &rp.r6, sizeof(rp.r6)) < 0) 127 goto bad; 128 di->packet_type_info = rp.r6.packet_mask; 129 130 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH, 131 &rp.r7, sizeof(rp.r7)) < 0) 132 goto bad; 133 di->role_switch_info = rp.r7.role_switch; 134 135 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &rp.r8, sizeof(rp.r8)) < 0) 136 goto bad; 137 di->debug = rp.r8.debug; 138 139 rval = 0; 140bad: 141 close(s); 142 143 return (rval); 144} 145 146int 147bt_devenum(bt_devenum_cb_t cb, void *arg) 148{ 149 struct ng_btsocket_hci_raw_node_list_names rp; 150 struct bt_devinfo di; 151 struct sockaddr_hci ha; 152 int s, i, count; 153 154 rp.num_names = HCI_DEVMAX; 155 rp.names = (struct nodeinfo *) calloc(rp.num_names, 156 sizeof(struct nodeinfo)); 157 if (rp.names == NULL) { 158 errno = ENOMEM; 159 return (-1); 160 } 161 162 memset(&ha, 0, sizeof(ha)); 163 ha.hci_len = sizeof(ha); 164 ha.hci_family = AF_BLUETOOTH; 165 ha.hci_node[0] = 'x'; 166 167 s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); 168 if (s < 0) { 169 free(rp.names); 170 171 return (-1); 172 } 173 174 if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || 175 connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || 176 ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &rp, sizeof(rp)) < 0) { 177 close(s); 178 free(rp.names); 179 180 return (-1); 181 } 182 183 for (count = 0, i = 0; i < rp.num_names; i ++) { 184 strlcpy(di.devname, rp.names[i].name, sizeof(di.devname)); 185 if (bt_devinfo(&di) < 0) 186 continue; 187 188 count ++; 189 190 if (cb == NULL) 191 continue; 192 193 strlcpy(ha.hci_node, rp.names[i].name, sizeof(ha.hci_node)); 194 if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 || 195 connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0) 196 continue; 197 198 if ((*cb)(s, &di, arg) > 0) 199 break; 200 } 201 202 close (s); 203 free(rp.names); 204 205 return (count); 206} 207 208static char * 209bt_dev2node(char const *devname, char *nodename, int nnlen) 210{ 211 static char const * bt_dev_prefix[] = { 212 "btccc", /* 3Com Bluetooth PC-CARD */ 213 "h4", /* UART/serial Bluetooth devices */ 214 "ubt", /* Bluetooth USB devices */ 215 NULL /* should be last */ 216 }; 217 218 static char _nodename[HCI_DEVNAME_SIZE]; 219 char const **p; 220 char *ep; 221 int plen, unit; 222 223 if (nodename == NULL) { 224 nodename = _nodename; 225 nnlen = HCI_DEVNAME_SIZE; 226 } 227 228 for (p = bt_dev_prefix; *p != NULL; p ++) { 229 plen = strlen(*p); 230 if (strncmp(devname, *p, plen) != 0) 231 continue; 232 233 unit = strtoul(devname + plen, &ep, 10); 234 if (*ep != '\0' && 235 strcmp(ep, "hci") != 0 && 236 strcmp(ep, "l2cap") != 0) 237 return (NULL); /* can't make sense of device name */ 238 239 snprintf(nodename, nnlen, "%s%uhci", *p, unit); 240 241 return (nodename); 242 } 243 244 return (NULL); 245} 246 247