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