1 /* $NetBSD: hci.c,v 1.3 2009/10/05 12:34:26 plunky Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Itronix Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of Itronix Inc. may not be used to endorse 16 * or promote products derived from this software without specific 17 * prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 * SUCH DAMAGE. 55 */ 56 57 #include <sys/cdefs.h> 58 __RCSID("$NetBSD: hci.c,v 1.3 2009/10/05 12:34:26 plunky Exp $"); 59 60 #include <sys/ioctl.h> 61 #include <sys/time.h> 62 #include <bluetooth.h> 63 #include <errno.h> 64 #include <event.h> 65 #include <string.h> 66 #include <syslog.h> 67 #include <unistd.h> 68 69 #include "bthcid.h" 70 71 static struct event hci_ev; 72 73 static void process_hci 74 (int, short, void *); 75 76 static int process_pin_code_request_event 77 (int, struct sockaddr_bt *, bdaddr_t *); 78 static int process_link_key_request_event 79 (int, struct sockaddr_bt *, bdaddr_t *); 80 static int process_link_key_notification_event 81 (int, struct sockaddr_bt *, hci_link_key_notification_ep *); 82 83 static int send_link_key_reply 84 (int, struct sockaddr_bt *, bdaddr_t *, uint8_t *); 85 static int send_hci_cmd 86 (int, struct sockaddr_bt *, uint16_t, size_t, void *); 87 88 static char dev_name[HCI_DEVNAME_SIZE]; 89 90 /* Initialise HCI Events */ 91 int 92 init_hci(const char *device) 93 { 94 struct bt_devfilter filter; 95 int hci; 96 97 hci = bt_devopen(device, 0); 98 if (hci < 0) 99 return -1; 100 101 memset(&filter, 0, sizeof(filter)); 102 bt_devfilter_pkt_set(&filter, HCI_EVENT_PKT); 103 bt_devfilter_evt_set(&filter, HCI_EVENT_PIN_CODE_REQ); 104 bt_devfilter_evt_set(&filter, HCI_EVENT_LINK_KEY_REQ); 105 bt_devfilter_evt_set(&filter, HCI_EVENT_LINK_KEY_NOTIFICATION); 106 if (bt_devfilter(hci, &filter, NULL) < 0) { 107 close(hci); 108 return -1; 109 } 110 111 event_set(&hci_ev, hci, EV_READ | EV_PERSIST, process_hci, NULL); 112 if (event_add(&hci_ev, NULL) < 0) { 113 close(hci); 114 return -1; 115 } 116 117 return 0; 118 } 119 120 /* Process an HCI event */ 121 static void 122 process_hci(int sock, short ev, void *arg) 123 { 124 char buffer[HCI_EVENT_PKT_SIZE]; 125 hci_event_hdr_t *event = (hci_event_hdr_t *)buffer; 126 struct sockaddr_bt addr; 127 int n; 128 socklen_t size; 129 130 size = sizeof(addr); 131 n = recvfrom(sock, buffer, sizeof(buffer), 0, 132 (struct sockaddr *) &addr, &size); 133 if (n < 0) { 134 syslog(LOG_ERR, "Could not receive from HCI socket: %m"); 135 return; 136 } 137 138 if (event->type != HCI_EVENT_PKT) { 139 syslog(LOG_ERR, "Received unexpected HCI packet, " 140 "type=%#x", event->type); 141 142 return; 143 } 144 145 if (!bt_devname(dev_name, &addr.bt_bdaddr)) 146 strlcpy(dev_name, "unknown", sizeof(dev_name)); 147 148 switch (event->event) { 149 case HCI_EVENT_PIN_CODE_REQ: 150 process_pin_code_request_event(sock, &addr, 151 (bdaddr_t *)(event + 1)); 152 break; 153 154 case HCI_EVENT_LINK_KEY_REQ: 155 process_link_key_request_event(sock, &addr, 156 (bdaddr_t *)(event + 1)); 157 break; 158 159 case HCI_EVENT_LINK_KEY_NOTIFICATION: 160 process_link_key_notification_event(sock, &addr, 161 (hci_link_key_notification_ep *)(event + 1)); 162 break; 163 164 default: 165 syslog(LOG_ERR, "Received unexpected HCI event, " 166 "event=%#x", event->event); 167 break; 168 } 169 170 return; 171 } 172 173 /* Process PIN_Code_Request event */ 174 static int 175 process_pin_code_request_event(int sock, struct sockaddr_bt *addr, 176 bdaddr_t *bdaddr) 177 { 178 uint8_t *pin; 179 180 syslog(LOG_DEBUG, "Got PIN_Code_Request event from %s, " 181 "remote bdaddr %s", 182 dev_name, 183 bt_ntoa(bdaddr, NULL)); 184 185 pin = lookup_pin(&addr->bt_bdaddr, bdaddr); 186 if (pin != NULL) 187 return send_pin_code_reply(sock, addr, bdaddr, pin); 188 189 if (send_client_request(&addr->bt_bdaddr, bdaddr, sock) == 0) 190 return send_pin_code_reply(sock, addr, bdaddr, NULL); 191 192 return 0; 193 } 194 195 /* Process Link_Key_Request event */ 196 static int 197 process_link_key_request_event(int sock, struct sockaddr_bt *addr, 198 bdaddr_t *bdaddr) 199 { 200 uint8_t *key; 201 202 syslog(LOG_DEBUG, 203 "Got Link_Key_Request event from %s, remote bdaddr %s", 204 dev_name, bt_ntoa(bdaddr, NULL)); 205 206 key = lookup_key(&addr->bt_bdaddr, bdaddr); 207 208 if (key != NULL) { 209 syslog(LOG_DEBUG, "Found Key, remote bdaddr %s", 210 bt_ntoa(bdaddr, NULL)); 211 212 return send_link_key_reply(sock, addr, bdaddr, key); 213 } 214 215 syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s", 216 bt_ntoa(bdaddr, NULL)); 217 218 return send_link_key_reply(sock, addr, bdaddr, NULL); 219 } 220 221 /* Send PIN_Code_[Negative]_Reply */ 222 int 223 send_pin_code_reply(int sock, struct sockaddr_bt *addr, 224 bdaddr_t *bdaddr, uint8_t *pin) 225 { 226 int n; 227 228 if (pin != NULL) { 229 hci_pin_code_rep_cp cp; 230 231 syslog(LOG_DEBUG, "Sending PIN_Code_Reply to %s " 232 "for remote bdaddr %s", 233 dev_name, 234 bt_ntoa(bdaddr, NULL)); 235 236 bdaddr_copy(&cp.bdaddr, bdaddr); 237 memcpy(cp.pin, pin, HCI_PIN_SIZE); 238 239 n = HCI_PIN_SIZE; 240 while (n > 0 && pin[n - 1] == 0) 241 n--; 242 cp.pin_size = n; 243 244 n = send_hci_cmd(sock, addr, 245 HCI_CMD_PIN_CODE_REP, sizeof(cp), &cp); 246 247 } else { 248 syslog(LOG_DEBUG, "Sending PIN_Code_Negative_Reply to %s " 249 "for remote bdaddr %s", 250 dev_name, 251 bt_ntoa(bdaddr, NULL)); 252 253 n = send_hci_cmd(sock, addr, HCI_CMD_PIN_CODE_NEG_REP, 254 sizeof(bdaddr_t), bdaddr); 255 } 256 257 if (n < 0) { 258 syslog(LOG_ERR, "Could not send PIN code reply to %s " 259 "for remote bdaddr %s: %m", 260 dev_name, 261 bt_ntoa(bdaddr, NULL)); 262 263 return -1; 264 } 265 266 return 0; 267 } 268 269 /* Send Link_Key_[Negative]_Reply */ 270 static int 271 send_link_key_reply(int sock, struct sockaddr_bt *addr, 272 bdaddr_t *bdaddr, uint8_t *key) 273 { 274 int n; 275 276 if (key != NULL) { 277 hci_link_key_rep_cp cp; 278 279 bdaddr_copy(&cp.bdaddr, bdaddr); 280 memcpy(&cp.key, key, sizeof(cp.key)); 281 282 syslog(LOG_DEBUG, "Sending Link_Key_Reply to %s " 283 "for remote bdaddr %s", 284 dev_name, bt_ntoa(bdaddr, NULL)); 285 286 n = send_hci_cmd(sock, addr, HCI_CMD_LINK_KEY_REP, sizeof(cp), &cp); 287 } else { 288 hci_link_key_neg_rep_cp cp; 289 290 bdaddr_copy(&cp.bdaddr, bdaddr); 291 292 syslog(LOG_DEBUG, "Sending Link_Key_Negative_Reply to %s " 293 "for remote bdaddr %s", 294 dev_name, bt_ntoa(bdaddr, NULL)); 295 296 n = send_hci_cmd(sock, addr, HCI_CMD_LINK_KEY_NEG_REP, sizeof(cp), &cp); 297 } 298 299 if (n < 0) { 300 syslog(LOG_ERR, "Could not send link key reply to %s " 301 "for remote bdaddr %s: %m", 302 dev_name, bt_ntoa(bdaddr, NULL)); 303 return -1; 304 } 305 306 return 0; 307 } 308 309 /* Process Link_Key_Notification event */ 310 static int 311 process_link_key_notification_event(int sock, struct sockaddr_bt *addr, 312 hci_link_key_notification_ep *ep) 313 { 314 315 syslog(LOG_DEBUG, "Got Link_Key_Notification event from %s, " 316 "remote bdaddr %s", 317 dev_name, 318 bt_ntoa(&ep->bdaddr, NULL)); 319 320 save_key(&addr->bt_bdaddr, &ep->bdaddr, ep->key); 321 return 0; 322 } 323 324 /* Send HCI Command Packet to socket */ 325 static int 326 send_hci_cmd(int sock, struct sockaddr_bt *sa, uint16_t opcode, size_t len, void *buf) 327 { 328 char msg[HCI_CMD_PKT_SIZE]; 329 hci_cmd_hdr_t *h = (hci_cmd_hdr_t *)msg; 330 331 h->type = HCI_CMD_PKT; 332 h->opcode = htole16(opcode); 333 h->length = len; 334 335 if (len > 0) 336 memcpy(msg + sizeof(hci_cmd_hdr_t), buf, len); 337 338 return sendto(sock, msg, sizeof(hci_cmd_hdr_t) + len, 0, 339 (struct sockaddr *)sa, sizeof(*sa)); 340 } 341