1 /* $NetBSD: hci.c,v 1.2 2007/01/25 20:33:41 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.2 2007/01/25 20:33:41 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(bdaddr_t *bdaddr) 93 { 94 struct sockaddr_bt sa; 95 struct hci_filter filter; 96 int hci; 97 98 hci = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 99 if (hci < 0) 100 return -1; 101 102 memset(&sa, 0, sizeof(sa)); 103 sa.bt_len = sizeof(sa); 104 sa.bt_family = AF_BLUETOOTH; 105 bdaddr_copy(&sa.bt_bdaddr, bdaddr); 106 if (bind(hci, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 107 close(hci); 108 return -1; 109 } 110 111 memset(&filter, 0, sizeof(filter)); 112 hci_filter_set(HCI_EVENT_PIN_CODE_REQ, &filter); 113 hci_filter_set(HCI_EVENT_LINK_KEY_REQ, &filter); 114 hci_filter_set(HCI_EVENT_LINK_KEY_NOTIFICATION, &filter); 115 116 if (setsockopt(hci, BTPROTO_HCI, SO_HCI_EVT_FILTER, 117 (const void *)&filter, sizeof(filter)) < 0) { 118 close(hci); 119 return -1; 120 } 121 122 event_set(&hci_ev, hci, EV_READ | EV_PERSIST, process_hci, NULL); 123 if (event_add(&hci_ev, NULL) < 0) { 124 close(hci); 125 return -1; 126 } 127 128 return 0; 129 } 130 131 /* Process an HCI event */ 132 static void 133 process_hci(int sock, short ev, void *arg) 134 { 135 char buffer[HCI_EVENT_PKT_SIZE]; 136 hci_event_hdr_t *event = (hci_event_hdr_t *)buffer; 137 struct sockaddr_bt addr; 138 int n; 139 socklen_t size; 140 141 size = sizeof(addr); 142 n = recvfrom(sock, buffer, sizeof(buffer), 0, 143 (struct sockaddr *) &addr, &size); 144 if (n < 0) { 145 syslog(LOG_ERR, "Could not receive from HCI socket: %m"); 146 return; 147 } 148 149 if (event->type != HCI_EVENT_PKT) { 150 syslog(LOG_ERR, "Received unexpected HCI packet, " 151 "type=%#x", event->type); 152 153 return; 154 } 155 156 if (!bt_devname(dev_name, &addr.bt_bdaddr)) 157 strlcpy(dev_name, "unknown", sizeof(dev_name)); 158 159 switch (event->event) { 160 case HCI_EVENT_PIN_CODE_REQ: 161 process_pin_code_request_event(sock, &addr, 162 (bdaddr_t *)(event + 1)); 163 break; 164 165 case HCI_EVENT_LINK_KEY_REQ: 166 process_link_key_request_event(sock, &addr, 167 (bdaddr_t *)(event + 1)); 168 break; 169 170 case HCI_EVENT_LINK_KEY_NOTIFICATION: 171 process_link_key_notification_event(sock, &addr, 172 (hci_link_key_notification_ep *)(event + 1)); 173 break; 174 175 default: 176 syslog(LOG_ERR, "Received unexpected HCI event, " 177 "event=%#x", event->event); 178 break; 179 } 180 181 return; 182 } 183 184 /* Process PIN_Code_Request event */ 185 static int 186 process_pin_code_request_event(int sock, struct sockaddr_bt *addr, 187 bdaddr_t *bdaddr) 188 { 189 uint8_t *pin; 190 191 syslog(LOG_DEBUG, "Got PIN_Code_Request event from %s, " 192 "remote bdaddr %s", 193 dev_name, 194 bt_ntoa(bdaddr, NULL)); 195 196 pin = lookup_pin(&addr->bt_bdaddr, bdaddr); 197 if (pin != NULL) 198 return send_pin_code_reply(sock, addr, bdaddr, pin); 199 200 if (send_client_request(&addr->bt_bdaddr, bdaddr, sock) == 0) 201 return send_pin_code_reply(sock, addr, bdaddr, NULL); 202 203 return 0; 204 } 205 206 /* Process Link_Key_Request event */ 207 static int 208 process_link_key_request_event(int sock, struct sockaddr_bt *addr, 209 bdaddr_t *bdaddr) 210 { 211 uint8_t *key; 212 213 syslog(LOG_DEBUG, 214 "Got Link_Key_Request event from %s, remote bdaddr %s", 215 dev_name, bt_ntoa(bdaddr, NULL)); 216 217 key = lookup_key(&addr->bt_bdaddr, bdaddr); 218 219 if (key != NULL) { 220 syslog(LOG_DEBUG, "Found Key, remote bdaddr %s", 221 bt_ntoa(bdaddr, NULL)); 222 223 return send_link_key_reply(sock, addr, bdaddr, key); 224 } 225 226 syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s", 227 bt_ntoa(bdaddr, NULL)); 228 229 return send_link_key_reply(sock, addr, bdaddr, NULL); 230 } 231 232 /* Send PIN_Code_[Negative]_Reply */ 233 int 234 send_pin_code_reply(int sock, struct sockaddr_bt *addr, 235 bdaddr_t *bdaddr, uint8_t *pin) 236 { 237 int n; 238 239 if (pin != NULL) { 240 hci_pin_code_rep_cp cp; 241 242 syslog(LOG_DEBUG, "Sending PIN_Code_Reply to %s " 243 "for remote bdaddr %s", 244 dev_name, 245 bt_ntoa(bdaddr, NULL)); 246 247 bdaddr_copy(&cp.bdaddr, bdaddr); 248 memcpy(cp.pin, pin, HCI_PIN_SIZE); 249 250 n = HCI_PIN_SIZE; 251 while (n > 0 && pin[n - 1] == 0) 252 n--; 253 cp.pin_size = n; 254 255 n = send_hci_cmd(sock, addr, 256 HCI_CMD_PIN_CODE_REP, sizeof(cp), &cp); 257 258 } else { 259 syslog(LOG_DEBUG, "Sending PIN_Code_Negative_Reply to %s " 260 "for remote bdaddr %s", 261 dev_name, 262 bt_ntoa(bdaddr, NULL)); 263 264 n = send_hci_cmd(sock, addr, HCI_CMD_PIN_CODE_NEG_REP, 265 sizeof(bdaddr_t), bdaddr); 266 } 267 268 if (n < 0) { 269 syslog(LOG_ERR, "Could not send PIN code reply to %s " 270 "for remote bdaddr %s: %m", 271 dev_name, 272 bt_ntoa(bdaddr, NULL)); 273 274 return -1; 275 } 276 277 return 0; 278 } 279 280 /* Send Link_Key_[Negative]_Reply */ 281 static int 282 send_link_key_reply(int sock, struct sockaddr_bt *addr, 283 bdaddr_t *bdaddr, uint8_t *key) 284 { 285 int n; 286 287 if (key != NULL) { 288 hci_link_key_rep_cp cp; 289 290 bdaddr_copy(&cp.bdaddr, bdaddr); 291 memcpy(&cp.key, key, sizeof(cp.key)); 292 293 syslog(LOG_DEBUG, "Sending Link_Key_Reply to %s " 294 "for remote bdaddr %s", 295 dev_name, bt_ntoa(bdaddr, NULL)); 296 297 n = send_hci_cmd(sock, addr, HCI_CMD_LINK_KEY_REP, sizeof(cp), &cp); 298 } else { 299 hci_link_key_neg_rep_cp cp; 300 301 bdaddr_copy(&cp.bdaddr, bdaddr); 302 303 syslog(LOG_DEBUG, "Sending Link_Key_Negative_Reply to %s " 304 "for remote bdaddr %s", 305 dev_name, bt_ntoa(bdaddr, NULL)); 306 307 n = send_hci_cmd(sock, addr, HCI_CMD_LINK_KEY_NEG_REP, sizeof(cp), &cp); 308 } 309 310 if (n < 0) { 311 syslog(LOG_ERR, "Could not send link key reply to %s " 312 "for remote bdaddr %s: %m", 313 dev_name, bt_ntoa(bdaddr, NULL)); 314 return -1; 315 } 316 317 return 0; 318 } 319 320 /* Process Link_Key_Notification event */ 321 static int 322 process_link_key_notification_event(int sock, struct sockaddr_bt *addr, 323 hci_link_key_notification_ep *ep) 324 { 325 326 syslog(LOG_DEBUG, "Got Link_Key_Notification event from %s, " 327 "remote bdaddr %s", 328 dev_name, 329 bt_ntoa(&ep->bdaddr, NULL)); 330 331 save_key(&addr->bt_bdaddr, &ep->bdaddr, ep->key); 332 return 0; 333 } 334 335 /* Send HCI Command Packet to socket */ 336 static int 337 send_hci_cmd(int sock, struct sockaddr_bt *sa, uint16_t opcode, size_t len, void *buf) 338 { 339 char msg[HCI_CMD_PKT_SIZE]; 340 hci_cmd_hdr_t *h = (hci_cmd_hdr_t *)msg; 341 342 h->type = HCI_CMD_PKT; 343 h->opcode = htole16(opcode); 344 h->length = len; 345 346 if (len > 0) 347 memcpy(msg + sizeof(hci_cmd_hdr_t), buf, len); 348 349 return sendto(sock, msg, sizeof(hci_cmd_hdr_t) + len, 0, 350 (struct sockaddr *)sa, sizeof(*sa)); 351 } 352