summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorUwe Stuehler <uwe@cvs.openbsd.org>2008-11-26 06:51:44 +0000
committerUwe Stuehler <uwe@cvs.openbsd.org>2008-11-26 06:51:44 +0000
commit82a67aa5c79659c28ace847e9d1ddbf8485e1a0c (patch)
tree76ae7602af14363a78a597b2f90a6d2b1f8cbd65 /usr.sbin
parent9dc81ca0a6153a852c7e65abefc7cc4718473541 (diff)
Implement config reloading (still only work in progress)
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/btd/Makefile6
-rw-r--r--usr.sbin/btd/atomicio.c75
-rw-r--r--usr.sbin/btd/bt.c39
-rw-r--r--usr.sbin/btd/bt_subr.c138
-rw-r--r--usr.sbin/btd/btd.c239
-rw-r--r--usr.sbin/btd/btd.h39
-rw-r--r--usr.sbin/btd/conf.c15
-rw-r--r--usr.sbin/btd/control.c16
-rw-r--r--usr.sbin/btd/fdpass.c112
-rw-r--r--usr.sbin/btd/hci.c528
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));