diff options
author | Uwe Stuehler <uwe@cvs.openbsd.org> | 2008-11-26 06:51:44 +0000 |
---|---|---|
committer | Uwe Stuehler <uwe@cvs.openbsd.org> | 2008-11-26 06:51:44 +0000 |
commit | 82a67aa5c79659c28ace847e9d1ddbf8485e1a0c (patch) | |
tree | 76ae7602af14363a78a597b2f90a6d2b1f8cbd65 /usr.sbin | |
parent | 9dc81ca0a6153a852c7e65abefc7cc4718473541 (diff) |
Implement config reloading (still only work in progress)
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/btd/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/btd/atomicio.c | 75 | ||||
-rw-r--r-- | usr.sbin/btd/bt.c | 39 | ||||
-rw-r--r-- | usr.sbin/btd/bt_subr.c | 138 | ||||
-rw-r--r-- | usr.sbin/btd/btd.c | 239 | ||||
-rw-r--r-- | usr.sbin/btd/btd.h | 39 | ||||
-rw-r--r-- | usr.sbin/btd/conf.c | 15 | ||||
-rw-r--r-- | usr.sbin/btd/control.c | 16 | ||||
-rw-r--r-- | usr.sbin/btd/fdpass.c | 112 | ||||
-rw-r--r-- | usr.sbin/btd/hci.c | 528 |
10 files changed, 928 insertions, 279 deletions
diff --git a/usr.sbin/btd/Makefile b/usr.sbin/btd/Makefile index ab5c4a92188..75c2f66b802 100644 --- a/usr.sbin/btd/Makefile +++ b/usr.sbin/btd/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.2 2008/11/25 17:13:53 uwe Exp $ +# $OpenBSD: Makefile,v 1.3 2008/11/26 06:51:43 uwe Exp $ PROG= btd -SRCS= bt.c bt_subr.c btd.c conf.c control.c db.c devinfo.c \ - hci.c log.c util.c +SRCS= atomicio.c bt.c bt_subr.c btd.c conf.c control.c db.c \ + devinfo.c fdpass.c hci.c log.c util.c NOMAN= LDADD+= -levent -lusbhid diff --git a/usr.sbin/btd/atomicio.c b/usr.sbin/btd/atomicio.c new file mode 100644 index 00000000000..017f1e77dad --- /dev/null +++ b/usr.sbin/btd/atomicio.c @@ -0,0 +1,75 @@ +/* $OpenBSD: atomicio.c,v 1.1 2008/11/26 06:51:43 uwe Exp $ */ + +/* + * Copyright (c) 2003 Can Erkin Acar + * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <unistd.h> + +#include "btd.h" + +/* Read data with the assertion that it all must come through, or + * else abort the process. Based on atomicio() from openssh. */ +int +atomic_read(int fd, void *buf, size_t n) +{ + char *s = buf; + ssize_t res, pos = 0; + + while (n > pos) { + res = read(fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + return -1; + case 0: + errno = 0; + return -1; + default: + pos += res; + } + } + + return 0; +} + +/* Write data with the assertion that it all has to be written, or + * else abort the process. Based on atomicio() from openssh. */ +int +atomic_write(int fd, const void *buf, size_t n) +{ + const char *s = buf; + ssize_t res, pos = 0; + + while (n > pos) { + res = write(fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + return -1; + case 0: + errno = 0; + return -1; + default: + pos += res; + } + } + + return 0; +} diff --git a/usr.sbin/btd/bt.c b/usr.sbin/btd/bt.c index 1a141c67651..08994c09caf 100644 --- a/usr.sbin/btd/bt.c +++ b/usr.sbin/btd/bt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bt.c,v 1.2 2008/11/25 17:13:53 uwe Exp $ */ +/* $OpenBSD: bt.c,v 1.3 2008/11/26 06:51:43 uwe Exp $ */ /* * Copyright (c) 2008 Uwe Stuehler <uwe@openbsd.org> @@ -42,14 +42,13 @@ struct event ev_sigint; struct event ev_sigterm; struct event ev_siginfo; -struct bufferevent *ev_priv; -void bt_priv_readcb(struct bufferevent *, void *); -void bt_priv_writecb(struct bufferevent *, void *); -void bt_priv_errorcb(struct bufferevent *, short, void *); +int priv_fd; void bt_sighdlr(int sig, short ev, void *arg) { + struct btd *env = arg; + switch (sig) { case SIGINT: case SIGTERM: @@ -57,7 +56,7 @@ bt_sighdlr(int sig, short ev, void *arg) break; case SIGINFO: - /* report status */ + conf_dump(env); break; } } @@ -107,15 +106,11 @@ bt_main(int pipe_prnt[2], struct btd *env, struct passwd *pw) close(pipe_prnt[0]); - if ((ev_priv = bufferevent_new(pipe_prnt[1], bt_priv_readcb, - bt_priv_writecb, bt_priv_errorcb, env)) == NULL) - fatalx("bufferevent_new ev_priv"); - - bufferevent_enable(ev_priv, EV_READ); + priv_fd = pipe_prnt[1]; - signal_set(&ev_sigint, SIGINT, bt_sighdlr, NULL); - signal_set(&ev_sigterm, SIGTERM, bt_sighdlr, NULL); - signal_set(&ev_siginfo, SIGINFO, bt_sighdlr, NULL); + signal_set(&ev_sigint, SIGINT, bt_sighdlr, env); + signal_set(&ev_sigterm, SIGTERM, bt_sighdlr, env); + signal_set(&ev_siginfo, SIGINFO, bt_sighdlr, env); signal_add(&ev_sigint, NULL); signal_add(&ev_sigterm, NULL); signal_add(&ev_siginfo, NULL); @@ -133,21 +128,21 @@ bt_main(int pipe_prnt[2], struct btd *env, struct passwd *pw) } void -bt_priv_readcb(struct bufferevent *ev, void *arg) +bt_priv_msg(enum imsg_type type) { - log_debug(__func__); + bt_priv_send(&type, sizeof(type)); } void -bt_priv_writecb(struct bufferevent *ev, void *arg) +bt_priv_send(const void *buf, size_t n) { - /* nothing to do */ - log_debug(__func__); + if (atomic_write(priv_fd, buf, n) < 0) + fatal("atomic_write"); } void -bt_priv_errorcb(struct bufferevent *ev, short what, void *arg) +bt_priv_recv(void *buf, size_t n) { - log_warnx("priv pipe error, what=%#x", what); - exit(0); + if (atomic_read(priv_fd, buf, n) < 0) + fatal("atomic_read"); } diff --git a/usr.sbin/btd/bt_subr.c b/usr.sbin/btd/bt_subr.c new file mode 100644 index 00000000000..cd4b4f7510e --- /dev/null +++ b/usr.sbin/btd/bt_subr.c @@ -0,0 +1,138 @@ +/* $OpenBSD: bt_subr.c,v 1.1 2008/11/26 06:51:43 uwe Exp $ */ +/* $NetBSD: bluetooth.c,v 1.1 2006/06/19 15:44:36 gdamore Exp $ */ + +/* + * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: bt_subr.c,v 1.1 2008/11/26 06:51:43 uwe Exp $ + * $FreeBSD: src/lib/libbluetooth/bluetooth.c,v 1.2 2004/03/05 08:10:17 markm Exp $ + */ + +#include <stdio.h> +#include <string.h> + +#include "btd.h" + +static int bt_hex_byte (char const *str); +static int bt_hex_nibble (char nibble); + +char const * +bt_ntoa(bdaddr_t const *ba, char str[18]) +{ + static char buffer[24]; + + if (str == NULL) + str = buffer; + + snprintf(str, 18, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]); + + return (str); +} + +int +bt_aton(char const *str, bdaddr_t *ba) +{ + int i, b; + char *end = NULL; + + memset(ba, 0, sizeof(*ba)); + + for (i = 5, end = strchr(str, ':'); + i > 0 && *str != '\0' && end != NULL; + i --, str = end + 1, end = strchr(str, ':')) { + switch (end - str) { + case 1: + b = bt_hex_nibble(str[0]); + break; + + case 2: + b = bt_hex_byte(str); + break; + + default: + b = -1; + break; + } + + if (b < 0) + return (0); + + ba->b[i] = b; + } + + if (i != 0 || end != NULL || *str == 0) + return (0); + + switch (strlen(str)) { + case 1: + b = bt_hex_nibble(str[0]); + break; + + case 2: + b = bt_hex_byte(str); + break; + + default: + b = -1; + break; + } + + if (b < 0) + return (0); + + ba->b[i] = b; + + return (1); +} + +static int +bt_hex_byte(char const *str) +{ + int n1, n2; + + if ((n1 = bt_hex_nibble(str[0])) < 0) + return (-1); + + if ((n2 = bt_hex_nibble(str[1])) < 0) + return (-1); + + return ((((n1 & 0x0f) << 4) | (n2 & 0x0f)) & 0xff); +} + +static int +bt_hex_nibble(char nibble) +{ + if ('0' <= nibble && nibble <= '9') + return (nibble - '0'); + + if ('a' <= nibble && nibble <= 'f') + return (nibble - 'a' + 0xa); + + if ('A' <= nibble && nibble <= 'F') + return (nibble - 'A' + 0xa); + + return (-1); +} diff --git a/usr.sbin/btd/btd.c b/usr.sbin/btd/btd.c index f2c04fec282..8957280e9b7 100644 --- a/usr.sbin/btd/btd.c +++ b/usr.sbin/btd/btd.c @@ -1,4 +1,22 @@ -/* $OpenBSD: btd.c,v 1.1 2008/11/24 23:34:42 uwe Exp $ */ +/* $OpenBSD: btd.c,v 1.2 2008/11/26 06:51:43 uwe Exp $ */ + +/* + * Copyright (c) 2008 Uwe Stuehler <uwe@openbsd.org> + * Copyright (c) 2003 Can Erkin Acar + * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include <sys/ioctl.h> #include <sys/wait.h> @@ -7,9 +25,9 @@ #include <err.h> #include <errno.h> -#include <event.h> #include <fcntl.h> #include <libgen.h> +#include <poll.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -18,27 +36,23 @@ #include "btd.h" -void sighdlr(int, short, void *); -__dead void usage(void); -int check_child(pid_t, const char *); +static void sighdlr(int); +static __dead void usage(void); +static int check_child(pid_t, const char *); +static int btd_read(void *, size_t); +static int btd_write(const void *, size_t); +static int dispatch_imsg(struct btd *); +static void btd_open_hci(struct btd *); +static void btd_set_link_policy(struct btd *); static const char *progname; -static int quit = 0; -static int reconfig = 0; -static int sigchld = 0; - -static struct event ev_sigchld; -static struct event ev_sighup; -static struct event ev_sigint; -static struct event ev_sigterm; -static struct bufferevent *ev_bt; - -static void readcb(struct bufferevent *, void *); -static void writecb(struct bufferevent *, void *); -static void errorcb(struct bufferevent *, short, void *); - -void -sighdlr(int sig, short what, void *arg) +static volatile sig_atomic_t quit = 0; +static volatile sig_atomic_t reconfig = 0; +static volatile sig_atomic_t sigchld = 0; +static int pipe_fd; + +static void +sighdlr(int sig) { switch (sig) { case SIGTERM: @@ -54,7 +68,7 @@ sighdlr(int sig, short what, void *arg) } } -__dead void +static __dead void usage(void) { fprintf(stderr, "usage: %s [-d]\n", progname); @@ -68,6 +82,7 @@ main(int argc, char *argv[]) pid_t chld_pid, pid; int pipe_chld[2]; struct passwd *pw; + struct pollfd pfd; int ch; progname = basename(argv[0]); @@ -115,29 +130,30 @@ main(int argc, char *argv[]) setproctitle("[priv]"); - /* only after daemon() */ - event_init(); - - signal_set(&ev_sigchld, SIGCHLD, sighdlr, &env); - signal_set(&ev_sighup, SIGHUP, sighdlr, &env); - signal_set(&ev_sigint, SIGINT, sighdlr, &env); - signal_set(&ev_sigterm, SIGTERM, sighdlr, &env); - signal_add(&ev_sigchld, NULL); - signal_add(&ev_sighup, NULL); - signal_add(&ev_sigint, NULL); - signal_add(&ev_sigterm, NULL); + signal(SIGCHLD, sighdlr); + signal(SIGTERM, sighdlr); + signal(SIGINT, sighdlr); + signal(SIGHUP, sighdlr); close(pipe_chld[1]); + pipe_fd = pipe_chld[0]; - if ((ev_bt = bufferevent_new(pipe_chld[0], readcb, - writecb, errorcb, &env)) == NULL) - fatalx("bufferevent_new ev_bt"); + while (quit == 0) { + int nfds; - bufferevent_enable(ev_bt, EV_READ); + pfd.fd = pipe_fd; + pfd.events = POLLIN; - while (quit == 0) { - if (!event_loop(EVLOOP_ONCE)) - quit = 1; + if ((nfds = poll(&pfd, 1, 0)) == -1) + if (errno != EINTR) { + log_warn("poll error"); + quit = 1; + } + + + if (pfd.revents & POLLIN) + if (dispatch_imsg(&env) == -1) + quit = 1; if (sigchld) { if (check_child(chld_pid, "child")) { @@ -146,9 +162,10 @@ main(int argc, char *argv[]) } sigchld = 0; } + } - signal_del(&ev_sigchld); + signal(SIGCHLD, SIG_DFL); if (chld_pid) kill(chld_pid, SIGTERM); @@ -187,57 +204,127 @@ check_child(pid_t pid, const char *pname) return (0); } -static void -readcb(struct bufferevent *ev, void *arg) +static int +btd_read(void *buf, size_t n) { - log_warnx("readcb"); + if (atomic_read(pipe_fd, buf, n) < 0) { + close(pipe_fd); + pipe_fd = -1; + quit = 1; + return -1; + } + + return 0; } -static void -writecb(struct bufferevent *ev, void *arg) +static int +btd_write(const void *buf, size_t n) +{ + if (atomic_write(pipe_fd, buf, n) < 0) { + close(pipe_fd); + pipe_fd = -1; + quit = 1; + return -1; + } + + return 0; +} + +static int +dispatch_imsg(struct btd *env) { - /* nothing to do here */ - log_warnx("writecb"); + enum imsg_type type; + + if (btd_read(&type, sizeof(type)) < 0) { + log_warnx("btd_read"); + return -1; + } + + switch (type) { + case IMSG_OPEN_HCI: + btd_open_hci(env); + break; + case IMSG_SET_LINK_POLICY: + btd_set_link_policy(env); + break; + default: + log_warnx("invalid message, type=%#x", type); + return -1; + } + + return 0; } static void -errorcb(struct bufferevent *ev, short what, void *arg) +btd_open_hci(struct btd *env) { - log_warnx("Pipe error"); - quit = 1; + struct sockaddr_bt sa; + bdaddr_t addr; + int fd; + int err = 0; + + if (btd_read(&addr, sizeof(addr)) < 0) + return; + + if ((fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) == -1) { + err = errno; + btd_write(&err, sizeof(err)); + return; + } + + bzero(&sa, sizeof(sa)); + sa.bt_len = sizeof(sa); + sa.bt_family = AF_BLUETOOTH; + bdaddr_copy(&sa.bt_bdaddr, &addr); + + if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0 || + connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { + err = errno; + close(fd); + fd = -1; + } + + send_fd(pipe_fd, fd); + + (void)btd_write(&err, sizeof(err)); + + if (fd != -1) + close(fd); } -#ifdef notyet -void -btd_devctl(struct imsg *imsg) +static void +btd_set_link_policy(struct btd *env) { - struct btdev_attach_args baa; - char buf[sizeof(int) + sizeof(bdaddr_t)]; - unsigned long cmd; - int res; + struct btreq btr; + bdaddr_t addr; + uint16_t link_policy; + int err = 0; int fd; - if (devinfo_load_attach_args(&baa, imsg->data, - imsg->hdr.len - IMSG_HEADER_SIZE)) - fatalx("invalid IMSG_ATTACH/DETACH received"); + if (btd_read(&addr, sizeof(addr)) < 0 || + btd_read(&link_policy, sizeof(link_policy)) < 0) + return; + + if ((fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) == -1) { + err = errno; + btd_write(&err, sizeof(err)); + return; + } + + bdaddr_copy(&btr.btr_bdaddr, &addr); - if ((fd = open(BTHUB_PATH, O_WRONLY, 0)) == -1) { - res = errno; - log_warn("can't open %s", BTHUB_PATH); - goto ret; + if (ioctl(fd, SIOCGBTINFOA, &btr) < 0) { + err = errno; + close(fd); + btd_write(&err, sizeof(err)); + return; } - cmd = imsg->hdr.type == IMSG_ATTACH ? BTDEV_ATTACH : BTDEV_DETACH; - if (ioctl(fd, cmd, &baa) == -1) - res = errno; + btr.btr_link_policy = link_policy; - res = 0; - (void)close(fd); -ret: - devinfo_unload_attach_args(&baa); + if (ioctl(fd, SIOCSBTPOLICY, &btr) < 0) + err = errno; - memcpy(buf, &res, sizeof(res)); - memcpy((int *)buf + 1, &baa.bd_raddr, sizeof(bdaddr_t)); - /* send reply */ + btd_write(&err, sizeof(err)); + close(fd); } -#endif diff --git a/usr.sbin/btd/btd.h b/usr.sbin/btd/btd.h index f51ff35ec33..73249bcc2e1 100644 --- a/usr.sbin/btd/btd.h +++ b/usr.sbin/btd/btd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: btd.h,v 1.2 2008/11/25 17:13:53 uwe Exp $ */ +/* $OpenBSD: btd.h,v 1.3 2008/11/26 06:51:43 uwe Exp $ */ /* * Copyright (c) 2008 Uwe Stuehler <uwe@openbsd.org> @@ -48,18 +48,15 @@ struct btd_db { struct bt_interface { TAILQ_ENTRY(bt_interface) entry; struct btd *env; - const char *xname; + struct hci_physif *physif; bdaddr_t addr; char name[HCI_UNIT_NAME_SIZE]; int disabled; - struct event ev; - int fd; -}; - -struct btd_hci { - struct bt_interface *inquiry_interface; - int inquiry_running; - time_t last_inquiry; /* start time */ + int flags; +#define BTIF_EXPLICIT 0x0001 /* listed in config */ + int changes; +#define BTIF_DELETED 0x0001 +#define BTIF_NAME_CHANGED 0x0002 }; struct bt_devinfo { @@ -73,8 +70,7 @@ struct bt_device { bdaddr_t addr; uint16_t type; uint8_t pin[HCI_PIN_SIZE]; - uint8_t pin_len; - time_t last_seen; /* last response to an inquiry */ + uint8_t pin_size; int flags; struct bt_devinfo info; }; @@ -85,7 +81,7 @@ struct bt_device { struct btd { int debug; struct btd_db db; - struct btd_hci hci; + struct hci_state *hci; TAILQ_HEAD(interfaces, bt_interface) interfaces; TAILQ_HEAD(devices, bt_device) devices; }; @@ -99,14 +95,24 @@ enum imsg_type { IMSG_CONFIG_DEVICE, IMSG_CONFIG_COMMIT, IMSG_CONFIG_ROLLBACK, + IMSG_OPEN_HCI, + IMSG_SET_LINK_POLICY, IMSG_ATTACH, IMSG_DETACH }; /* prototypes */ +/* atomic.c */ +int atomic_read(int, void *, size_t); +int atomic_write(int, const void *, size_t); + /* bt.c */ +extern int priv_fd; pid_t bt_main(int[2], struct btd *, struct passwd *); +void bt_priv_msg(enum imsg_type); +void bt_priv_send(const void *, size_t); +void bt_priv_recv(void *, size_t); /* bt_subr.c */ char const *bt_ntoa(bdaddr_t const *, char[18]); @@ -150,10 +156,13 @@ int devinfo_load_attach_args(struct btdev_attach_args *, void *, size_t); void devinfo_unload_attach_args(struct btdev_attach_args *); void devinfo_dump(const struct bt_devinfo *); +/* fdpass.c */ +void send_fd(int, int); +int receive_fd(int); + /* hci.c */ int hci_init(struct btd *); -time_t hci_ping(struct btd *); -int hci_dispatch(int, struct btd *); +int hci_reinit(struct btd *, const struct btd *); /* log.c */ extern int debug; diff --git a/usr.sbin/btd/conf.c b/usr.sbin/btd/conf.c index c29d95abf6d..7eee71ec2b1 100644 --- a/usr.sbin/btd/conf.c +++ b/usr.sbin/btd/conf.c @@ -50,7 +50,6 @@ conf_add_interface(struct btd *conf, const bdaddr_t *addr) iface->env = conf; bdaddr_copy(&iface->addr, addr); - iface->fd = -1; TAILQ_INSERT_TAIL(&conf->interfaces, iface, entry); @@ -128,19 +127,19 @@ conf_delete_device(struct bt_device *btdev) void conf_lookup_pin(const struct btd *conf, const bdaddr_t *addr, - uint8_t pin[HCI_PIN_SIZE], uint8_t *pin_len) + uint8_t pin[HCI_PIN_SIZE], uint8_t *pin_size) { struct bt_device *btdev; if ((btdev = conf_find_device(conf, addr)) == NULL && (btdev = conf_find_device(conf, BDADDR_ANY)) == NULL) { memset(pin, 0, HCI_PIN_SIZE); - *pin_len = 0; + *pin_size = 0; return; } memcpy(pin, btdev->pin, HCI_PIN_SIZE); - *pin_len = btdev->pin_len; + *pin_size = btdev->pin_size; } void @@ -150,11 +149,15 @@ conf_dump(const struct btd *conf) struct bt_device *btdev; TAILQ_FOREACH(iface, &conf->interfaces, entry) { - log_info("interface %s", bt_ntoa(&iface->addr, NULL)); + log_debug("interface %s%s", bt_ntoa(&iface->addr, NULL), + iface->disabled ? " disabled" : ""); } TAILQ_FOREACH(btdev, &conf->devices, entry) { - log_info("device %s", bt_ntoa(&btdev->addr, NULL)); + log_debug("device %s type %#x%s%*s%s", + bt_ntoa(&btdev->addr, NULL), btdev->type, + btdev->pin_size > 0 ? " pin \"" : "", btdev->pin_size, + btdev->pin, btdev->pin_size > 0 ? "\"" : ""); } } diff --git a/usr.sbin/btd/control.c b/usr.sbin/btd/control.c index 39ad760a47d..12ba9014a92 100644 --- a/usr.sbin/btd/control.c +++ b/usr.sbin/btd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.2 2008/11/25 17:13:53 uwe Exp $ */ +/* $OpenBSD: control.c,v 1.3 2008/11/26 06:51:43 uwe Exp $ */ /* * Copyright (c) 2008 Uwe Stuehler <uwe@openbsd.org> @@ -181,7 +181,7 @@ control_readcb(struct bufferevent *ev, void *arg) return; bufferevent_read(ev, &stmt_type, sizeof(stmt_type)); - log_debug("stmt %#x size %lu", stmt_type, stmt_size); + /*log_debug("stmt %#x size %lu", stmt_type, stmt_size);*/ switch (stmt_type) { case BTCTL_CONFIG: @@ -280,7 +280,7 @@ control_attach_stmt(struct btd *conf, btctl_attach_stmt *stmt) btdev->type = stmt->type; strlcpy(btdev->pin, stmt->pin, sizeof(btdev->pin)); - btdev->pin_len = stmt->pin_len; + btdev->pin_size = stmt->pin_size; btdev->flags |= BTDF_ATTACH; @@ -290,13 +290,5 @@ control_attach_stmt(struct btd *conf, btctl_attach_stmt *stmt) int control_commit(struct btd *env, const struct btd *conf) { -#if 0 - struct bt_interface *iface; - struct bt_interface *conf_iface; -#endif - - conf_dump(env); - conf_dump(conf); - - return 0; + return hci_reinit(env, conf); } diff --git a/usr.sbin/btd/fdpass.c b/usr.sbin/btd/fdpass.c new file mode 100644 index 00000000000..e49764a07de --- /dev/null +++ b/usr.sbin/btd/fdpass.c @@ -0,0 +1,112 @@ +/* $OpenBSD: fdpass.c,v 1.1 2008/11/26 06:51:43 uwe Exp $ */ + +/* + * Copyright (c) 2002 Matthieu Herrb + * Copyright (c) 2001 Niels Provos <provos@citi.umich.edu> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +#include "btd.h" + +void +send_fd(int sock, int fd) +{ + struct msghdr msg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + struct cmsghdr *cmsg; + struct iovec vec; + int result = 0; + ssize_t n; + + memset(&msg, 0, sizeof(msg)); + + if (fd >= 0) { + msg.msg_control = (caddr_t)&cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = fd; + } else + result = errno; + + vec.iov_base = &result; + vec.iov_len = sizeof(int); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + + if ((n = sendmsg(sock, &msg, 0)) == -1) + warn("%s: sendmsg(%d)", __func__, sock); + if (n != sizeof(int)) + warnx("%s: sendmsg: expected sent 1 got %ld", + __func__, (long)n); +} + +int +receive_fd(int sock) +{ + struct msghdr msg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + struct cmsghdr *cmsg; + struct iovec vec; + ssize_t n; + int result; + int fd; + + memset(&msg, 0, sizeof(msg)); + vec.iov_base = &result; + vec.iov_len = sizeof(int); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + + if ((n = recvmsg(sock, &msg, 0)) == -1) + warn("%s: recvmsg", __func__); + if (n != sizeof(int)) + warnx("%s: recvmsg: expected received 1 got %ld", + __func__, (long)n); + if (result == 0) { + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg == NULL) { + warnx("%s: no message header", __func__); + return (-1); + } + if (cmsg->cmsg_type != SCM_RIGHTS) + warnx("%s: expected type %d got %d", __func__, + SCM_RIGHTS, cmsg->cmsg_type); + fd = (*(int *)CMSG_DATA(cmsg)); + return (fd); + } else { + errno = result; + return (-1); + } +} diff --git a/usr.sbin/btd/hci.c b/usr.sbin/btd/hci.c index d5e8ec90ea9..b8b0e31e0c1 100644 --- a/usr.sbin/btd/hci.c +++ b/usr.sbin/btd/hci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hci.c,v 1.2 2008/11/25 17:13:53 uwe Exp $ */ +/* $OpenBSD: hci.c,v 1.3 2008/11/26 06:51:43 uwe Exp $ */ /* $NetBSD: btconfig.c,v 1.13 2008/07/21 13:36:57 lukem Exp $ */ /*- @@ -44,208 +44,434 @@ #include "btd.h" -#define MIN(a, b) ((a) < (b) ? (a) : (b)) +struct hci_physif { + TAILQ_ENTRY(hci_physif) entry; + struct btd *env; + int present; + bdaddr_t addr; + char xname[16]; + struct event ev; + int fd; +}; + +struct hci_state { + TAILQ_HEAD(, hci_physif) physifs; + int raw_sock; +}; + +void hci_update_physifs(struct btd *); +struct hci_physif *hci_find_physif(struct hci_state *, bdaddr_t *); -int hci_init_config(struct bt_interface *); +void hci_if_config(struct bt_interface *, const struct bt_interface *); +void hci_if_apply(struct bt_interface *); + +int hci_interface_open(struct bt_interface *); +void hci_interface_close(struct bt_interface *); +int hci_interface_reinit(struct bt_interface *); void hci_eventcb(int, short, void *); -int hci_process_pin_code_req(struct bt_interface *, +int hci_process_pin_code_req(struct hci_physif *, struct sockaddr_bt *, const bdaddr_t *); -int hci_process_link_key_req(struct bt_interface *, +int hci_process_link_key_req(struct hci_physif *, struct sockaddr_bt *, const bdaddr_t *); -int hci_process_link_key_notification(struct bt_interface *, struct sockaddr_bt *, - const hci_link_key_notification_ep *); +int hci_process_link_key_notification(struct hci_physif *, + struct sockaddr_bt *, const hci_link_key_notification_ep *); int hci_req(int, uint16_t, uint8_t , void *, size_t, void *, size_t); int hci_send_cmd(int, struct sockaddr_bt *, uint16_t, size_t, void *); -#define hci_write(iface, opcode, wbuf, wlen) \ - hci_req(iface->fd, opcode, 0, wbuf, wlen, NULL, 0) -#define hci_read(iface, opcode, rbuf, rlen) \ - hci_req(iface->fd, opcode, 0, NULL, 0, rbuf, rlen) -#define hci_cmd(iface, opcode, cbuf, clen) \ - hci_req(iface->fd, opcode, 0, cbuf, clen, NULL, 0) +#define hci_write(fd, opcode, wbuf, wlen) \ + hci_req(fd, opcode, 0, wbuf, wlen, NULL, 0) +#define hci_read(fd, opcode, rbuf, rlen) \ + hci_req(fd, opcode, 0, NULL, 0, rbuf, rlen) +#define hci_cmd(fd, opcode, cbuf, clen) \ + hci_req(fd, opcode, 0, cbuf, clen, NULL, 0) + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) int hci_init(struct btd *env) { - struct btreq btr; - struct bt_interface *defaults; - struct bt_interface *iface; - int hci; + struct hci_state *hci; + + hci = env->hci = calloc(1, sizeof(*env->hci)); - hci = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); - if (hci == -1) + hci->raw_sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (hci->raw_sock == -1) fatal("could not open raw HCI socket"); - defaults = conf_find_interface(env, BDADDR_ANY); - iface = NULL; + TAILQ_INIT(&hci->physifs); + + return 0; +} + +void +hci_update_physifs(struct btd *env) +{ + struct btreq btr; + struct hci_state *hci = env->hci; + struct hci_physif *physif; + int sock; bzero(&btr, sizeof(btr)); + sock = hci->raw_sock; + + TAILQ_FOREACH(physif, &hci->physifs, entry) + physif->present = 0; + for (;;) { int flags; - if (ioctl(hci, SIOCNBTINFO, &btr) == -1) + if (ioctl(sock, SIOCNBTINFO, &btr) < 0) break; /* - * Interfaces must be up, just to determine their - * bdaddr. Grrrr... + * XXX Interfaces must be up, just to determine their + * XXX bdaddr. Grrrr... */ - if (!((flags = btr.btr_flags) & BTF_UP)) { + if (!((flags = btr.btr_flags) & BTF_UP) || + bdaddr_any(&btr.btr_bdaddr)) { btr.btr_flags |= BTF_UP; - if (ioctl(hci, SIOCSBTFLAGS, &btr) == -1) { + if (ioctl(sock, SIOCSBTFLAGS, &btr) < 0) { log_warn("%s: SIOCSBTFLAGS", btr.btr_name); continue; } - if (ioctl(hci, SIOCGBTINFO, &btr) == -1) { + if (ioctl(sock, SIOCGBTINFO, &btr) < 0) { log_warn("%s: SIOCGBTINFO", btr.btr_name); continue; } + if (!(btr.btr_flags & BTF_UP) || + bdaddr_any(&btr.btr_bdaddr)) { + log_warnx("could not enable %s", + btr.btr_name); + goto redisable; + } } - if (!(btr.btr_flags & BTF_UP) || - bdaddr_any(&btr.btr_bdaddr)) { - log_warn("could not enable %s", btr.btr_name); - goto redisable; + if ((physif = hci_find_physif(hci, &btr.btr_bdaddr))) { + physif->present = 1; + goto found; } - /* - * Discover device driver unit names for explicitly - * configured interfaces. - */ - iface = conf_find_interface(env, &btr.btr_bdaddr); - if (iface != NULL) { - assert(iface->xname == NULL); - iface->xname = strdup(btr.btr_name); - if (iface->xname == NULL) - fatal("hci_init strdup 1"); - goto redisable; - } + if ((physif = calloc(1, sizeof(*physif))) == NULL) + fatalx("hci physif calloc"); - /* - * Add interfaces not explicitly configured. - */ - iface = conf_add_interface(env, &btr.btr_bdaddr); - if (iface == NULL) - fatalx("hci_init add_interface"); + physif->env = env; + physif->fd = -1; + physif->present = 1; + bdaddr_copy(&physif->addr, &btr.btr_bdaddr); + strlcpy(physif->xname, btr.btr_name, sizeof(physif->xname)); + + TAILQ_INSERT_TAIL(&hci->physifs, physif, entry); - iface->xname = strdup(btr.btr_name); - if (iface->xname == NULL) - fatal("hci_init strdup 2"); + found: + (void)conf_add_interface(env, &physif->addr); redisable: - /* See above. Grrrr... */ - if (!(flags & BTF_UP) && - (iface == NULL || iface->disabled)) { + /* XXX See above. Grrrr... */ + if (!(flags & BTF_UP)) { btr.btr_flags &= ~BTF_UP; - if (ioctl(hci, SIOCSBTFLAGS, &btr) == -1) + if (ioctl(sock, SIOCSBTFLAGS, &btr) < 0) fatal("hci_init SIOCSBTFLAGS"); } } - close(hci); + for (physif = TAILQ_FIRST(&hci->physifs); physif != NULL;) { + if (!physif->present) { + struct hci_physif *next; + struct bt_interface *iface; - TAILQ_FOREACH(iface, &env->interfaces, entry) { - struct sockaddr_bt sa; - struct hci_filter filter; - - if (bdaddr_any(&iface->addr)) - continue; + iface = conf_find_interface(env, &physif->addr); + if (iface != NULL) { + hci_interface_close(iface); + conf_delete_interface(iface); + } - /* Disable interfaces not present in the system. */ - if (iface->xname == NULL) { - iface->disabled = 1; - log_info("interface disabled: %s (not present)", - bt_ntoa(&iface->addr, NULL)); + next = TAILQ_NEXT(physif, entry); + TAILQ_REMOVE(&hci->physifs, physif, entry); + free(physif); + physif = next; continue; } - /* Skip manually disabled interfaces. */ - if (iface->disabled) { - log_info("interface disabled: %s (%s)", - bt_ntoa(&iface->addr, NULL), iface->xname); - continue; + physif = TAILQ_NEXT(physif, entry); + } +} + +struct hci_physif * +hci_find_physif(struct hci_state *hci, bdaddr_t *addr) +{ + struct hci_physif *physif; + + TAILQ_FOREACH(physif, &hci->physifs, entry) + if (bdaddr_same(&physif->addr, addr)) + return physif; + + return NULL; +} + +int +hci_reinit(struct btd *env, const struct btd *conf) +{ + struct bt_interface *conf_iface; + struct bt_interface *iface; + struct bt_device *conf_btdev; + struct bt_device *btdev; + + hci_update_physifs(env); + + /* + * "Downgrade" all explicit interfaces, which are not in the + * configuration anymore. + */ + TAILQ_FOREACH(iface, &env->interfaces, entry) { + conf_iface = conf_find_interface(conf, &iface->addr); + if (conf_iface == NULL) + iface->flags &= ~BTIF_EXPLICIT; + } + + /* + * Add new interfaces from the configuration and mark the + * changed properties of existing interfaces. The wildcard + * interface is not treated specially in this loop. + */ + TAILQ_FOREACH(conf_iface, &conf->interfaces, entry) { + iface = conf_find_interface(env, &conf_iface->addr); + + if (iface == NULL) { + iface = conf_add_interface(env, &conf_iface->addr); + if (iface == NULL) { + int err = errno; + log_warn("could not add interface %s", + bt_ntoa(&conf_iface->addr, NULL)); + errno = err; + return -1; + } + + iface->changes |= BTIF_NAME_CHANGED; } - log_info("listening on %s (%s)", - bt_ntoa(&iface->addr, NULL), iface->xname); - - iface->fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); - if (iface->fd == -1) - fatal("socket"); - - bzero(&sa, sizeof(sa)); - sa.bt_len = sizeof(sa); - sa.bt_family = AF_BLUETOOTH; - bdaddr_copy(&sa.bt_bdaddr, &iface->addr); - if (bind(iface->fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) - fatal("bind"); - - if (connect(iface->fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) - fatal("connect"); - - if (hci_init_config(iface) == -1) - fatalx("hci_init_config"); - - bzero(&filter, sizeof(filter)); - hci_filter_set(HCI_EVENT_PIN_CODE_REQ, &filter); - hci_filter_set(HCI_EVENT_LINK_KEY_REQ, &filter); - hci_filter_set(HCI_EVENT_LINK_KEY_NOTIFICATION, &filter); - if (setsockopt(iface->fd, BTPROTO_HCI, SO_HCI_EVT_FILTER, - (const void *)&filter, sizeof(filter)) < 0) - fatal("setsockopt"); - - event_set(&iface->ev, iface->fd, EV_READ | EV_PERSIST, - hci_eventcb, iface); - event_add(&iface->ev, NULL); + iface->flags |= BTIF_EXPLICIT; + + hci_if_config(iface, conf_iface); } /* - * Run device discovery on the first available - * interface. This should be configurable. + * Apply the changes in the wildcard interface to all + * non-explicit interfaces. If there is no wildcard interface, + * delete all non-explicit interfaces. */ + conf_iface = conf_find_interface(conf, BDADDR_ANY); TAILQ_FOREACH(iface, &env->interfaces, entry) { - if (!bdaddr_any(&iface->addr) && !iface->disabled) { - env->hci.inquiry_interface = iface; - break; + if (!(iface->flags & BTIF_EXPLICIT)) { + if (conf_iface != NULL) + hci_if_config(iface, conf_iface); + else + iface->changes |= BTIF_DELETED; + } + } + + /* + * Apply all interface changes now. + */ + for (iface = TAILQ_FIRST(&env->interfaces); iface != NULL;) { + if (iface->changes & BTIF_DELETED) { + struct bt_interface *next; + + hci_interface_close(iface); + + next = TAILQ_NEXT(iface, entry); + conf_delete_interface(iface); + iface = next; + continue; + } + + if (!bdaddr_any(&iface->addr)) + hci_if_apply(iface); + + iface = TAILQ_NEXT(iface, entry); + } + + TAILQ_FOREACH(btdev, &env->devices, entry) { + conf_btdev = conf_find_device(conf, &btdev->addr); + if (conf_btdev == NULL) { + struct bt_device *next; + + /* XXX detach */ + + next = TAILQ_NEXT(btdev, entry); + conf_delete_device(btdev); + btdev = next; + continue; } } + TAILQ_FOREACH(conf_btdev, &conf->devices, entry) { + btdev = conf_find_device(env, &conf_btdev->addr); + if (btdev == NULL) { + btdev = conf_add_device(env, &conf_btdev->addr); + if (btdev == NULL) { + int err = errno; + log_warn("could not add device %s", + bt_ntoa(&conf_btdev->addr, NULL)); + errno = err; + return -1; + } + } + + btdev->type = conf_btdev->type; + + memcpy(btdev->pin, conf_btdev->pin, sizeof(btdev->pin)); + btdev->pin_size = conf_btdev->pin_size; + } + + return 0; +} + +void +hci_if_config(struct bt_interface *iface, const struct bt_interface *other) +{ + if (memcmp(iface->name, other->name, sizeof(iface->name))) { + iface->changes |= BTIF_NAME_CHANGED; + memcpy(iface->name, other->name, sizeof(iface->name)); + } + + iface->disabled = other->disabled; +} + +void +hci_if_apply(struct bt_interface *iface) +{ + if (iface->disabled) { + hci_interface_close(iface); + return; + } + + if (hci_interface_open(iface) < 0) + return; + + if (iface->changes != 0) { + (void)hci_interface_reinit(iface); + iface->changes = 0; + } +} + +int +hci_interface_open(struct bt_interface *iface) +{ + struct hci_filter filter; + struct hci_state *hci = iface->env->hci; + struct hci_physif *physif; + int err; + + if (iface->physif == NULL) { + iface->physif = hci_find_physif(hci, &iface->addr); + if (iface->physif == NULL) + /* no physical interface to open, but that's ok */ + return 0; + } + + physif = iface->physif; + + if (physif->fd != -1) + return 0; + + bt_priv_msg(IMSG_OPEN_HCI); + bt_priv_send(&physif->addr, sizeof(bdaddr_t)); + physif->fd = receive_fd(priv_fd); + bt_priv_recv(&err, sizeof(int)); + if (err != 0) { + log_warnx("OPEN_HCI failed (%s)", strerror(err)); + return -1; + } + + memset(&filter, 0, sizeof(filter)); + hci_filter_set(HCI_EVENT_COMMAND_STATUS, &filter); + hci_filter_set(HCI_EVENT_COMMAND_COMPL, &filter); + hci_filter_set(HCI_EVENT_PIN_CODE_REQ, &filter); + hci_filter_set(HCI_EVENT_LINK_KEY_REQ, &filter); + hci_filter_set(HCI_EVENT_LINK_KEY_NOTIFICATION, &filter); + if (setsockopt(physif->fd, BTPROTO_HCI, SO_HCI_EVT_FILTER, + &filter, sizeof(filter)) < 0) { + log_warn("SO_HCI_EVT_FILTER"); + return -1; + } + + event_set(&physif->ev, physif->fd, EV_READ|EV_PERSIST, + &hci_eventcb, physif); + if (event_add(&physif->ev, NULL)) { + log_warnx("event_add"); + return -1; + } + + log_info("listening on %s", bt_ntoa(&physif->addr, NULL)); return 0; } +void +hci_interface_close(struct bt_interface *iface) +{ + struct hci_physif *physif = iface->physif; + + if (physif == NULL) + return; + + if (physif->fd != -1) { + close(physif->fd); + physif->fd = -1; + } + + iface->physif = NULL; +} + int -hci_init_config(struct bt_interface *iface) +hci_interface_reinit(struct bt_interface *iface) { struct btreq btr; + struct hci_physif *physif; uint8_t val; + int err; - if (hci_write(iface, HCI_CMD_WRITE_LOCAL_NAME, iface->name, - HCI_UNIT_NAME_SIZE)) - return -1; + if ((physif = iface->physif) == NULL) + /* no physical interface, so we keep changes pending */ + return 0; + + if (iface->changes & BTIF_NAME_CHANGED) { + if (hci_write(physif->fd, HCI_CMD_WRITE_LOCAL_NAME, + iface->name, HCI_UNIT_NAME_SIZE)) + return -1; + iface->changes &= ~BTIF_NAME_CHANGED; + } + + /* The rest is unconditional configuration. */ - if (hci_read(iface, HCI_CMD_READ_SCAN_ENABLE, &val, sizeof(val))) + if (hci_read(physif->fd, HCI_CMD_READ_SCAN_ENABLE, &val, + sizeof(val))) return -1; val |= HCI_PAGE_SCAN_ENABLE; val |= HCI_INQUIRY_SCAN_ENABLE; - if (hci_write(iface, HCI_CMD_WRITE_SCAN_ENABLE, &val, sizeof(val))) + if (hci_write(physif->fd, HCI_CMD_WRITE_SCAN_ENABLE, &val, + sizeof(val))) return -1; - bdaddr_copy(&btr.btr_bdaddr, &iface->addr); - if (ioctl(iface->fd, SIOCGBTINFOA, &btr) < 0) { + bdaddr_copy(&btr.btr_bdaddr, &physif->addr); + + if (ioctl(physif->fd, SIOCGBTINFOA, &btr) < 0) { log_warn("SIOCGBTINFOA"); return -1; } - val = btr.btr_link_policy; - val |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH; - btr.btr_link_policy = val; + btr.btr_link_policy |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH; + + bt_priv_msg(IMSG_SET_LINK_POLICY); + bt_priv_send(&physif->addr, sizeof(bdaddr_t)); + bt_priv_send(&btr.btr_link_policy, sizeof(uint16_t)); + bt_priv_recv(&err, sizeof(int)); - if (ioctl(iface->fd, SIOCSBTPOLICY, &btr) < 0) { - log_warn("SIOCSBTPOLICY"); + if (err != 0) { + log_warnx("SET_LINK_POLICY failed (%s)", strerror(err)); return -1; } @@ -257,26 +483,31 @@ hci_eventcb(int fd, short evflags, void *arg) { char buf[HCI_EVENT_PKT_SIZE]; hci_event_hdr_t *event = (hci_event_hdr_t *)buf; - struct bt_interface *iface = arg; + struct hci_physif *physif = arg; struct sockaddr_bt sa; socklen_t size; bdaddr_t *addr; void *ep; int n; - if (iface == NULL) + if (physif == NULL) fatal("HCI event on closed socket?"); size = sizeof(sa); - n = recvfrom(iface->fd, buf, sizeof(buf), 0, + n = recvfrom(physif->fd, buf, sizeof(buf), 0, (struct sockaddr *)&sa, &size); if (n < 0) { log_warn("could not receive from HCI socket"); return; } + if (n < sizeof(hci_event_hdr_t)) { + log_warnx("short HCI packet"); + return; + } + if (event->type != HCI_EVENT_PKT) { - log_packet(&sa.bt_bdaddr, &iface->addr, + log_packet(&sa.bt_bdaddr, &physif->addr, "unexpected HCI packet, type=%#x", event->type); return; } @@ -284,74 +515,81 @@ hci_eventcb(int fd, short evflags, void *arg) addr = (bdaddr_t *)(event + 1); ep = (bdaddr_t *)(event + 1); + /* XXX check packet size */ switch (event->event) { + case HCI_EVENT_COMMAND_STATUS: + case HCI_EVENT_COMMAND_COMPL: + break; + case HCI_EVENT_PIN_CODE_REQ: - hci_process_pin_code_req(iface, &sa, addr); + hci_process_pin_code_req(physif, &sa, addr); break; case HCI_EVENT_LINK_KEY_REQ: - hci_process_link_key_req(iface, &sa, addr); + hci_process_link_key_req(physif, &sa, addr); break; case HCI_EVENT_LINK_KEY_NOTIFICATION: - hci_process_link_key_notification(iface, &sa, ep); + hci_process_link_key_notification(physif, &sa, ep); break; default: - log_packet(&sa.bt_bdaddr, &iface->addr, + log_packet(&sa.bt_bdaddr, &physif->addr, "unexpected HCI event, event=%#x", event->event); break; } } int -hci_process_pin_code_req(struct bt_interface *iface, +hci_process_pin_code_req(struct hci_physif *physif, struct sockaddr_bt *sa, const bdaddr_t *addr) { hci_pin_code_rep_cp cp; + struct btd *env = physif->env; + int fd = physif->fd; - conf_lookup_pin(iface->env, addr, cp.pin, &cp.pin_size); + conf_lookup_pin(env, addr, cp.pin, &cp.pin_size); if (cp.pin_size == 0) { log_info("%s: PIN code not found", bt_ntoa(addr, NULL)); - return hci_send_cmd(iface->fd, sa, HCI_CMD_PIN_CODE_NEG_REP, + return hci_send_cmd(fd, sa, HCI_CMD_PIN_CODE_NEG_REP, sizeof(bdaddr_t), (void *)addr); } else { - bdaddr_copy(&cp.bdaddr, addr); - log_info("%s: PIN code found", bt_ntoa(addr, NULL)); - return hci_send_cmd(iface->fd, sa, HCI_CMD_PIN_CODE_REP, + bdaddr_copy(&cp.bdaddr, addr); + return hci_send_cmd(fd, sa, HCI_CMD_PIN_CODE_REP, sizeof(cp), &cp); } } int -hci_process_link_key_req(struct bt_interface *iface, - struct sockaddr_bt *sa, const bdaddr_t *addr) +hci_process_link_key_req(struct hci_physif *physif, struct sockaddr_bt *sa, + const bdaddr_t *addr) { hci_link_key_rep_cp cp; + struct btd *env = physif->env; + int fd = physif->fd; - if (db_get_link_key(&iface->env->db, addr, cp.key)) { + if (db_get_link_key(&env->db, addr, cp.key)) { log_info("%s: link key not found", bt_ntoa(addr, NULL)); - return hci_send_cmd(iface->fd, sa, HCI_CMD_LINK_KEY_NEG_REP, + return hci_send_cmd(fd, sa, HCI_CMD_LINK_KEY_NEG_REP, sizeof(bdaddr_t), (void *)addr); } log_info("%s: link key found", bt_ntoa(addr, NULL)); bdaddr_copy(&cp.bdaddr, addr); - - return hci_send_cmd(iface->fd, sa, HCI_CMD_LINK_KEY_REP, - sizeof(cp), &cp); + return hci_send_cmd(fd, sa, HCI_CMD_LINK_KEY_REP, sizeof(cp), &cp); } int -hci_process_link_key_notification(struct bt_interface *iface, +hci_process_link_key_notification(struct hci_physif *physif, struct sockaddr_bt *sa, const hci_link_key_notification_ep *ep) { const bdaddr_t *addr = &ep->bdaddr; + struct btd *env = physif->env; int res; - if ((res = db_put_link_key(&iface->env->db, addr, ep->key)) == 0) + if ((res = db_put_link_key(&env->db, addr, ep->key)) == 0) log_info("%s: link key stored", bt_ntoa(addr, NULL)); else log_info("%s: link key not stored", bt_ntoa(addr, NULL)); |