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