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