summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruwe <uwe@openbsd.org>2008-11-26 15:32:56 +0000
committeruwe <uwe@openbsd.org>2008-11-26 15:32:56 +0000
commitaa9ef95f93fcf03f4691e00df56d3a2f890d0dd3 (patch)
treefabccd2ddc3bbd97ff5cf17e10c6b2b5a008702b
parentAdd my copyright here, too. (diff)
downloadwireguard-openbsd-aa9ef95f93fcf03f4691e00df56d3a2f890d0dd3.tar.xz
wireguard-openbsd-aa9ef95f93fcf03f4691e00df56d3a2f890d0dd3.zip
Device attach and detach (does not work because SDP is not implemented yet)
-rw-r--r--usr.sbin/btd/Makefile4
-rw-r--r--usr.sbin/btd/bt.c214
-rw-r--r--usr.sbin/btd/btd.c81
-rw-r--r--usr.sbin/btd/btd.h19
-rw-r--r--usr.sbin/btd/conf.c7
-rw-r--r--usr.sbin/btd/hci.c35
-rw-r--r--usr.sbin/btd/sdp.c738
7 files changed, 330 insertions, 768 deletions
diff --git a/usr.sbin/btd/Makefile b/usr.sbin/btd/Makefile
index 75c2f66b802..35ca5020fb8 100644
--- a/usr.sbin/btd/Makefile
+++ b/usr.sbin/btd/Makefile
@@ -1,8 +1,8 @@
-# $OpenBSD: Makefile,v 1.3 2008/11/26 06:51:43 uwe Exp $
+# $OpenBSD: Makefile,v 1.4 2008/11/26 15:32:56 uwe Exp $
PROG= btd
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
+ devinfo.c fdpass.c hci.c log.c sdp.c util.c
NOMAN=
LDADD+= -levent -lusbhid
diff --git a/usr.sbin/btd/bt.c b/usr.sbin/btd/bt.c
index 08994c09caf..57da5e3ee4c 100644
--- a/usr.sbin/btd/bt.c
+++ b/usr.sbin/btd/bt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bt.c,v 1.3 2008/11/26 06:51:43 uwe Exp $ */
+/* $OpenBSD: bt.c,v 1.4 2008/11/26 15:32:56 uwe Exp $ */
/*
* Copyright (c) 2008 Uwe Stuehler <uwe@openbsd.org>
@@ -38,9 +38,19 @@
void bt_sighdlr(int, short, void *);
+struct bt_interface *bt_find_inquiry_interface(struct btd *);
+struct bt_interface *bt_find_attach_interface(struct bt_device *);
+
+void bt_check_devices(int, short, void *);
+
+int bt_get_devinfo(struct bt_device *);
+int bt_device_attach(struct bt_device *);
+int bt_device_detach(struct bt_device *);
+
struct event ev_sigint;
struct event ev_sigterm;
struct event ev_siginfo;
+struct event ev_check_devices;
int priv_fd;
@@ -80,14 +90,10 @@ bt_main(int pipe_prnt[2], struct btd *env, struct passwd *pw)
setproctitle("bt engine");
event_init();
-
hid_init(NULL);
-
db_open(BTD_DB, &env->db);
-
- if (hci_init(env))
- fatalx("can't set up HCI listeners");
-
+ hci_init(env);
+ sdp_init(env);
control_init(env);
if (stat(pw->pw_dir, &stb) == -1)
@@ -119,6 +125,8 @@ bt_main(int pipe_prnt[2], struct btd *env, struct passwd *pw)
signal(SIGHUP, SIG_IGN);
signal(SIGCHLD, SIG_DFL);
+ evtimer_set(&ev_check_devices, bt_check_devices, env);
+
log_info("bt engine ready");
(void)event_dispatch();
@@ -146,3 +154,195 @@ bt_priv_recv(void *buf, size_t n)
if (atomic_read(priv_fd, buf, n) < 0)
fatal("atomic_read");
}
+
+struct bt_interface *
+bt_find_inquiry_interface(struct btd *env)
+{
+ struct bt_interface *iface;
+
+ TAILQ_FOREACH(iface, &env->interfaces, entry) {
+ if (iface->physif != NULL)
+ return iface;
+ }
+
+ return NULL;
+}
+
+struct bt_interface *
+bt_find_attach_interface(struct bt_device *btdev)
+{
+ struct bt_interface *iface;
+
+ TAILQ_FOREACH_REVERSE(iface, &btdev->env->interfaces,
+ interfaces, entry) {
+ if (iface->physif != NULL)
+ return iface;
+ }
+
+ return NULL;
+}
+
+void
+bt_devices_changed(void)
+{
+ struct timeval tv;
+
+ memset(&tv, 0, sizeof(tv));
+ evtimer_add(&ev_check_devices, &tv);
+}
+
+void
+bt_check_devices(int fd, short evflags, void *arg)
+{
+ struct btd *env = arg;
+ struct bt_device *btdev;
+
+ for (btdev = TAILQ_FIRST(&env->devices); btdev != NULL;) {
+ if ((btdev->flags & (BTDF_ATTACH|BTDF_ATTACH_DONE)) ==
+ BTDF_ATTACH_DONE) {
+ if (bt_device_detach(btdev) < 0) {
+ btdev = TAILQ_NEXT(btdev, entry);
+ continue;
+ }
+
+ if (!(btdev->flags & BTDF_ATTACH))
+ log_info("%s: device is now detached",
+ bt_ntoa(&btdev->addr, NULL));
+ }
+
+ if (btdev->flags & BTDF_DELETED) {
+ struct bt_device *next;
+
+ next = TAILQ_NEXT(btdev, entry);
+ conf_delete_device(btdev);
+ btdev = next;
+ continue;
+ }
+
+ if ((btdev->flags & (BTDF_ATTACH|BTDF_ATTACH_DONE)) ==
+ BTDF_ATTACH) {
+ if (bt_device_attach(btdev) < 0) {
+ btdev = TAILQ_NEXT(btdev, entry);
+ continue;
+ }
+
+ if (btdev->flags & BTDF_ATTACH_DONE)
+ log_info("%s: device is now attached",
+ bt_ntoa(&btdev->addr, NULL));
+ }
+
+ btdev = TAILQ_NEXT(btdev, entry);
+ }
+}
+
+int
+bt_get_devinfo(struct bt_device *btdev)
+{
+ struct btd *env = btdev->env;
+ int res;
+
+ res = db_get_devinfo(&env->db, &btdev->addr, &btdev->info);
+ if (res < 0)
+ return -1;
+ else if (res != 0) {
+ /* try sdp query */
+ return 0;
+ }
+
+ bdaddr_copy(&btdev->info.baa.bd_raddr, &btdev->addr);
+ btdev->flags |= BTDF_DEVINFO_VALID;
+ return 0;
+}
+
+int
+bt_device_attach(struct bt_device *btdev)
+{
+ struct bt_interface *iface;
+ void *buf;
+ size_t n;
+ int err;
+
+ if (btdev->flags & BTDF_ATTACH_DONE)
+ return 0;
+
+ if (!(btdev->flags & BTDF_DEVINFO_VALID)) {
+ if (bt_get_devinfo(btdev) < 0)
+ return -1;
+ if (!(btdev->flags & BTDF_DEVINFO_VALID))
+ return 0;
+ }
+
+ if (bdaddr_any(&btdev->info.baa.bd_laddr)) {
+ if ((iface = bt_find_attach_interface(btdev)) == NULL)
+ return 0;
+
+ bdaddr_copy(&btdev->info.baa.bd_laddr, &iface->addr);
+ }
+
+ if (devinfo_store(&btdev->info, &buf, &n) < 0)
+ return -1;
+
+ bt_priv_msg(IMSG_ATTACH);
+ bt_priv_send(&n, sizeof(n));
+ bt_priv_send(buf, n);
+ bt_priv_recv(&err, sizeof(int));
+ free(buf);
+
+ switch (err) {
+ case 0:
+ case EADDRINUSE:
+ btdev->flags |= BTDF_ATTACH_DONE;
+ return 0;
+ default:
+ log_warnx("could not attach %s (%s)",
+ bt_ntoa(&btdev->addr, NULL), strerror(err));
+ return -1;
+ }
+}
+
+int
+bt_device_detach(struct bt_device *btdev)
+{
+ struct bt_interface *iface;
+ void *buf;
+ size_t n;
+ int err;
+
+ if ((btdev->flags & BTDF_ATTACH) ||
+ !(btdev->flags & BTDF_ATTACH_DONE))
+ return 0;
+
+ if (!(btdev->flags & BTDF_DEVINFO_VALID)) {
+ if (bt_get_devinfo(btdev) < 0)
+ return -1;
+ if (!(btdev->flags & BTDF_DEVINFO_VALID))
+ return 0;
+ }
+
+ if (bdaddr_any(&btdev->info.baa.bd_laddr)) {
+ if ((iface = bt_find_attach_interface(btdev)) == NULL)
+ return 0;
+
+ bdaddr_copy(&btdev->info.baa.bd_laddr, &iface->addr);
+ }
+
+ if (devinfo_store(&btdev->info, &buf, &n) < 0)
+ return -1;
+
+ bt_priv_msg(IMSG_DETACH);
+ bt_priv_send(&n, sizeof(n));
+ bt_priv_send(buf, n);
+ bt_priv_recv(&err, sizeof(int));
+ free(buf);
+
+ switch (err) {
+ case 0:
+ case ENODEV:
+ btdev->flags &= ~BTDF_ATTACH_DONE;
+ return 0;
+ default:
+ log_warnx("could not detach %s (%s)",
+ bt_ntoa(&btdev->addr, NULL), strerror(err));
+ return -1;
+ }
+}
diff --git a/usr.sbin/btd/btd.c b/usr.sbin/btd/btd.c
index 8957280e9b7..e365e5eeabc 100644
--- a/usr.sbin/btd/btd.c
+++ b/usr.sbin/btd/btd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: btd.c,v 1.2 2008/11/26 06:51:43 uwe Exp $ */
+/* $OpenBSD: btd.c,v 1.3 2008/11/26 15:32:56 uwe Exp $ */
/*
* Copyright (c) 2008 Uwe Stuehler <uwe@openbsd.org>
@@ -39,11 +39,12 @@
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 read_all(void *, size_t);
+static int write_all(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 void btd_devctl(struct btd *, enum imsg_type);
static const char *progname;
static volatile sig_atomic_t quit = 0;
@@ -205,7 +206,7 @@ check_child(pid_t pid, const char *pname)
}
static int
-btd_read(void *buf, size_t n)
+read_all(void *buf, size_t n)
{
if (atomic_read(pipe_fd, buf, n) < 0) {
close(pipe_fd);
@@ -218,7 +219,7 @@ btd_read(void *buf, size_t n)
}
static int
-btd_write(const void *buf, size_t n)
+write_all(const void *buf, size_t n)
{
if (atomic_write(pipe_fd, buf, n) < 0) {
close(pipe_fd);
@@ -235,8 +236,8 @@ dispatch_imsg(struct btd *env)
{
enum imsg_type type;
- if (btd_read(&type, sizeof(type)) < 0) {
- log_warnx("btd_read");
+ if (read_all(&type, sizeof(type)) < 0) {
+ log_warnx("read_all");
return -1;
}
@@ -247,6 +248,10 @@ dispatch_imsg(struct btd *env)
case IMSG_SET_LINK_POLICY:
btd_set_link_policy(env);
break;
+ case IMSG_ATTACH:
+ case IMSG_DETACH:
+ btd_devctl(env, type);
+ break;
default:
log_warnx("invalid message, type=%#x", type);
return -1;
@@ -263,12 +268,12 @@ btd_open_hci(struct btd *env)
int fd;
int err = 0;
- if (btd_read(&addr, sizeof(addr)) < 0)
+ if (read_all(&addr, sizeof(addr)) < 0)
return;
if ((fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) == -1) {
err = errno;
- btd_write(&err, sizeof(err));
+ write_all(&err, sizeof(err));
return;
}
@@ -286,7 +291,7 @@ btd_open_hci(struct btd *env)
send_fd(pipe_fd, fd);
- (void)btd_write(&err, sizeof(err));
+ (void)write_all(&err, sizeof(err));
if (fd != -1)
close(fd);
@@ -301,13 +306,13 @@ btd_set_link_policy(struct btd *env)
int err = 0;
int fd;
- if (btd_read(&addr, sizeof(addr)) < 0 ||
- btd_read(&link_policy, sizeof(link_policy)) < 0)
+ if (read_all(&addr, sizeof(addr)) < 0 ||
+ read_all(&link_policy, sizeof(link_policy)) < 0)
return;
if ((fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) == -1) {
err = errno;
- btd_write(&err, sizeof(err));
+ write_all(&err, sizeof(err));
return;
}
@@ -316,7 +321,7 @@ btd_set_link_policy(struct btd *env)
if (ioctl(fd, SIOCGBTINFOA, &btr) < 0) {
err = errno;
close(fd);
- btd_write(&err, sizeof(err));
+ write_all(&err, sizeof(err));
return;
}
@@ -325,6 +330,52 @@ btd_set_link_policy(struct btd *env)
if (ioctl(fd, SIOCSBTPOLICY, &btr) < 0)
err = errno;
- btd_write(&err, sizeof(err));
+ write_all(&err, sizeof(err));
close(fd);
}
+
+void
+btd_devctl(struct btd *env, enum imsg_type type)
+{
+ struct btdev_attach_args baa;
+ unsigned long cmd;
+ void *data;
+ size_t datalen;
+ int res = 0;
+ int fd;
+
+ if (read_all(&datalen, sizeof(datalen)) < 0)
+ return;
+
+ if (datalen < sizeof(baa) || datalen > sizeof(baa) + 65536)
+ fatalx("invalid data length in IMSG_ATTACH/DETACH");
+
+ if ((data = malloc(datalen)) == NULL)
+ fatal("btd_devctl");
+
+ if (read_all(data, datalen) < 0) {
+ free(data);
+ return;
+ }
+
+ if (devinfo_load_attach_args(&baa, data, datalen))
+ fatalx("invalid IMSG_ATTACH/DETACH received");
+
+ if ((fd = open(BTHUB_PATH, O_WRONLY, 0)) == -1) {
+ res = errno;
+ goto ret;
+ }
+
+ cmd = type == IMSG_ATTACH ? BTDEV_ATTACH : BTDEV_DETACH;
+ if (ioctl(fd, cmd, &baa) != 0)
+ res = errno;
+
+ (void)close(fd);
+ret:
+ if (data != NULL)
+ free(data);
+
+ devinfo_unload_attach_args(&baa);
+
+ write_all(&res, sizeof(res));
+}
diff --git a/usr.sbin/btd/btd.h b/usr.sbin/btd/btd.h
index 73249bcc2e1..3b390d8abc1 100644
--- a/usr.sbin/btd/btd.h
+++ b/usr.sbin/btd/btd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: btd.h,v 1.3 2008/11/26 06:51:43 uwe Exp $ */
+/* $OpenBSD: btd.h,v 1.4 2008/11/26 15:32:56 uwe Exp $ */
/*
* Copyright (c) 2008 Uwe Stuehler <uwe@openbsd.org>
@@ -72,16 +72,21 @@ struct bt_device {
uint8_t pin[HCI_PIN_SIZE];
uint8_t pin_size;
int flags;
- struct bt_devinfo info;
+ struct bt_devinfo info; /* filled in from database or SDP */
};
-#define BTDF_VISIBLE 0x0001 /* device is discoverable */
-#define BTDF_ATTACH 0x0002 /* attempt to attach a driver */
+#define BTDF_ATTACH 0x0001 /* try attaching a driver */
+#define BTDF_ATTACH_DONE 0x0002 /* driver is attached */
+#define BTDF_SDP_STARTED 0x0004 /* SDP query is running */
+#define BTDF_SDP_DONE 0x0008 /* SDP query is done */
+#define BTDF_DEVINFO_VALID 0x0010 /* got device information */
+#define BTDF_DELETED 0x0020 /* device deleted in config */
struct btd {
int debug;
struct btd_db db;
struct hci_state *hci;
+ struct sdp_state *sdp;
TAILQ_HEAD(interfaces, bt_interface) interfaces;
TAILQ_HEAD(devices, bt_device) devices;
};
@@ -113,6 +118,7 @@ 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);
+void bt_devices_changed(void);
/* bt_subr.c */
char const *bt_ntoa(bdaddr_t const *, char[18]);
@@ -161,7 +167,7 @@ void send_fd(int, int);
int receive_fd(int);
/* hci.c */
-int hci_init(struct btd *);
+void hci_init(struct btd *);
int hci_reinit(struct btd *, const struct btd *);
/* log.c */
@@ -177,7 +183,8 @@ void fatal(const char *);
void fatalx(const char *);
/* sdp.c */
-int sdp_query(struct btdev_attach_args *, bdaddr_t *, bdaddr_t *, const char *);
+void sdp_init(struct btd *);
+int sdp_query(struct bt_interface *, struct bt_device *);
/* util.c */
time_t getmonotime(void);
diff --git a/usr.sbin/btd/conf.c b/usr.sbin/btd/conf.c
index 7eee71ec2b1..04f72506cf7 100644
--- a/usr.sbin/btd/conf.c
+++ b/usr.sbin/btd/conf.c
@@ -154,10 +154,13 @@ conf_dump(const struct btd *conf)
}
TAILQ_FOREACH(btdev, &conf->devices, entry) {
- log_debug("device %s type %#x%s%*s%s",
+ log_debug("%s %s type %#x%s%*s%s (%s)",
+ btdev->flags & BTDF_ATTACH ? "attach" : "device",
bt_ntoa(&btdev->addr, NULL), btdev->type,
btdev->pin_size > 0 ? " pin \"" : "", btdev->pin_size,
- btdev->pin, btdev->pin_size > 0 ? "\"" : "");
+ btdev->pin, btdev->pin_size > 0 ? "\"" : "",
+ btdev->flags & BTDF_ATTACH_DONE ? "attached" :
+ "detached");
}
}
diff --git a/usr.sbin/btd/hci.c b/usr.sbin/btd/hci.c
index b8b0e31e0c1..a8070bcf84d 100644
--- a/usr.sbin/btd/hci.c
+++ b/usr.sbin/btd/hci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hci.c,v 1.3 2008/11/26 06:51:43 uwe Exp $ */
+/* $OpenBSD: hci.c,v 1.4 2008/11/26 15:32:56 uwe Exp $ */
/* $NetBSD: btconfig.c,v 1.13 2008/07/21 13:36:57 lukem Exp $ */
/*-
@@ -89,7 +89,7 @@ int hci_send_cmd(int, struct sockaddr_bt *, uint16_t, size_t, void *);
#define MIN(a, b) ((a) < (b) ? (a) : (b))
-int
+void
hci_init(struct btd *env)
{
struct hci_state *hci;
@@ -101,8 +101,6 @@ hci_init(struct btd *env)
fatal("could not open raw HCI socket");
TAILQ_INIT(&hci->physifs);
-
- return 0;
}
void
@@ -295,36 +293,29 @@ hci_reinit(struct btd *env, const struct btd *conf)
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;
+ btdev->flags &= ~BTDF_ATTACH;
+ btdev->flags |= BTDF_DELETED;
}
}
TAILQ_FOREACH(conf_btdev, &conf->devices, entry) {
btdev = conf_find_device(env, &conf_btdev->addr);
- if (btdev == NULL) {
+ 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;
- }
- }
+ if (btdev == NULL)
+ fatal("hci_reinit conf_add_device");
btdev->type = conf_btdev->type;
memcpy(btdev->pin, conf_btdev->pin, sizeof(btdev->pin));
btdev->pin_size = conf_btdev->pin_size;
+
+ btdev->flags |= conf_btdev->flags & BTDF_ATTACH;
+
}
+ bt_devices_changed();
+
return 0;
}
@@ -422,6 +413,8 @@ hci_interface_close(struct bt_interface *iface)
}
iface->physif = NULL;
+
+ log_info("stopped listening on %s", bt_ntoa(&physif->addr, NULL));
}
int
diff --git a/usr.sbin/btd/sdp.c b/usr.sbin/btd/sdp.c
index 06ec58382ce..9aae4eb7ef7 100644
--- a/usr.sbin/btd/sdp.c
+++ b/usr.sbin/btd/sdp.c
@@ -1,737 +1,45 @@
-/* $OpenBSD: sdp.c,v 1.2 2008/11/25 17:13:53 uwe Exp $ */
-/* $NetBSD: sdp.c,v 1.5 2008/04/20 19:34:23 plunky Exp $ */
+/* $OpenBSD: sdp.c,v 1.3 2008/11/26 15:32:56 uwe Exp $ */
-/*-
- * Copyright (c) 2006 Itronix Inc.
- * 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.
- * 3. The name of Itronix Inc. may not be used to endorse
- * or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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.
- */
/*
- * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
- * All rights reserved.
+ * Copyright (c) 2008 Uwe Stuehler <uwe@openbsd.org>
*
- * 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.
+ * 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.
*
- * 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.
+ * 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/types.h>
-
-#include <dev/bluetooth/btdev.h>
-#include <dev/usb/usb.h>
-#include <dev/usb/usbhid.h>
-
-#include <err.h>
-#include <errno.h>
-#include <sdp.h>
#include <stdlib.h>
-#include <usbhid.h>
#include "btd.h"
-static int hid_mode(uint8_t *, int32_t);
-
-static int32_t parse_l2cap_psm(sdp_attr_t *);
-static int32_t parse_rfcomm_channel(sdp_attr_t *);
-static int32_t parse_hid_descriptor(sdp_attr_t *);
-static int32_t parse_boolean(sdp_attr_t *);
-
-static int config_hid(struct btdev_attach_args *);
-static int config_hset(struct btdev_attach_args *);
-static int config_hf(struct btdev_attach_args *);
-
-uint16_t hid_services[] = {
- SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE
-};
-
-uint32_t hid_attrs[] = {
- SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
- SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
- SDP_ATTR_RANGE( SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS,
- SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS),
- SDP_ATTR_RANGE( 0x0205, /* HIDReconnectInitiate */
- 0x0206), /* HIDDescriptorList */
- SDP_ATTR_RANGE( 0x0209, /* HIDBatteryPower */
- 0x0209),
- SDP_ATTR_RANGE( 0x020d, /* HIDNormallyConnectable */
- 0x020d)
+struct sdp_session {
+ TAILQ_ENTRY(sdp_session) entry;
};
-uint16_t hset_services[] = {
- SDP_SERVICE_CLASS_HEADSET
+struct sdp_state {
+ TAILQ_HEAD(, sdp_session) sessions;
};
-uint32_t hset_attrs[] = {
- SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
- SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
-};
-
-uint16_t hf_services[] = {
- SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY
-};
-
-uint32_t hf_attrs[] = {
- SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
- SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST),
-};
-
-#define NUM(v) (sizeof(v) / sizeof(v[0]))
-
-static struct {
- const char *name;
- int (*handler)(struct btdev_attach_args *);
- const char *description;
- uint16_t *services;
- int nservices;
- uint32_t *attrs;
- int nattrs;
-} cfgtype[] = {
- {
- "HID", config_hid, "Human Interface Device",
- hid_services, NUM(hid_services),
- hid_attrs, NUM(hid_attrs),
- },
- {
- "HSET", config_hset, "Headset",
- hset_services, NUM(hset_services),
- hset_attrs, NUM(hset_attrs),
- },
- {
- "HF", config_hf, "Handsfree",
- hf_services, NUM(hf_services),
- hf_attrs, NUM(hf_attrs),
- },
-};
-
-static sdp_attr_t values[8];
-static uint8_t buffer[NUM(values)][512];
-
-int
-sdp_query(struct btdev_attach_args *dict,
- bdaddr_t *laddr, bdaddr_t *raddr, const char *service)
-{
- void *ss;
- int rv, i;
-
- for (i = 0 ; i < NUM(values) ; i++) {
- values[i].flags = SDP_ATTR_INVALID;
- values[i].attr = 0;
- values[i].vlen = sizeof(buffer[i]);
- values[i].value = buffer[i];
- }
-
- for (i = 0 ; i < NUM(cfgtype) ; i++) {
- if (strcasecmp(service, cfgtype[i].name) == 0) {
- ss = sdp_open(laddr, raddr);
-
- if (ss == NULL || (errno = sdp_error(ss)) != 0)
- return -1;
-
- rv = sdp_search(ss,
- cfgtype[i].nservices, cfgtype[i].services,
- cfgtype[i].nattrs, cfgtype[i].attrs,
- NUM(values), values);
-
- if (rv != 0) {
- errno = sdp_error(ss);
- return -1;
- }
- sdp_close(ss);
-
- rv = (*cfgtype[i].handler)(dict);
- if (rv != 0)
- return -1;
-
- return 0;
- }
- }
-
- fatalx("bad device type");
- /* NOTREACHED */
- return -1;
-}
-
-/*
- * Configure HID results
- */
-static int
-config_hid(struct btdev_attach_args *dict)
-{
- int32_t control_psm, interrupt_psm,
- reconnect_initiate, battery_power,
- normally_connectable, hid_length;
- uint8_t *hid_descriptor;
- int i;
-
- control_psm = -1;
- interrupt_psm = -1;
- reconnect_initiate = -1;
- normally_connectable = 0;
- battery_power = 0;
- hid_descriptor = NULL;
- hid_length = -1;
-
- for (i = 0; i < NUM(values) ; i++) {
- if (values[i].flags != SDP_ATTR_OK)
- continue;
-
- switch (values[i].attr) {
- case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
- control_psm = parse_l2cap_psm(&values[i]);
- break;
-
- case SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS:
- interrupt_psm = parse_l2cap_psm(&values[i]);
- break;
-
- case 0x0205: /* HIDReconnectInitiate */
- reconnect_initiate = parse_boolean(&values[i]);
- break;
-
- case 0x0206: /* HIDDescriptorList */
- if (parse_hid_descriptor(&values[i]) == 0) {
- hid_descriptor = values[i].value;
- hid_length = values[i].vlen;
- }
- break;
-
- case 0x0209: /* HIDBatteryPower */
- battery_power = parse_boolean(&values[i]);
- break;
-
- case 0x020d: /* HIDNormallyConnectable */
- normally_connectable = parse_boolean(&values[i]);
- break;
- }
- }
-
- if (control_psm == -1
- || interrupt_psm == -1
- || reconnect_initiate == -1
- || hid_descriptor == NULL
- || hid_length == -1)
- return ENOATTR;
-
- dict->bd_type = BTDEV_HID;
- dict->bd_hid.hid_ctl = control_psm;
- dict->bd_hid.hid_int = interrupt_psm;
- dict->bd_hid.hid_desc = hid_descriptor;
- dict->bd_hid.hid_dlen = hid_length;
- dict->bd_mode = hid_mode(hid_descriptor, hid_length);
-
- if (!reconnect_initiate)
- dict->bd_hid.hid_flags |= BTHID_INITIATE;
-
- return 0;
-}
-
-/*
- * Configure HSET results
- */
-static int
-config_hset(struct btdev_attach_args *dict)
+void
+sdp_init(struct btd *env)
{
- uint32_t channel;
- int i;
-
- channel = -1;
-
- for (i = 0; i < NUM(values) ; i++) {
- if (values[i].flags != SDP_ATTR_OK)
- continue;
-
- switch (values[i].attr) {
- case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
- channel = parse_rfcomm_channel(&values[i]);
- break;
- }
- }
+ struct sdp_state *sdp;
- if (channel == -1)
- return ENOATTR;
+ sdp = env->sdp = calloc(1, sizeof(*env->sdp));
- dict->bd_type = BTDEV_HSET;
- dict->bd_hset.hset_channel = channel;
-
- return 0;
+ TAILQ_INIT(&sdp->sessions);
}
-/*
- * Configure HF results
- */
-static int
-config_hf(struct btdev_attach_args *dict)
+int
+sdp_query(struct bt_interface *iface, struct bt_device *btdev)
{
- uint32_t channel;
- int i;
-
- channel = -1;
-
- for (i = 0 ; i < NUM(values) ; i++) {
- if (values[i].flags != SDP_ATTR_OK)
- continue;
-
- switch (values[i].attr) {
- case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST:
- channel = parse_rfcomm_channel(&values[i]);
- break;
- }
- }
-
- if (channel == -1)
- return ENOATTR;
-
- dict->bd_type = BTDEV_HF;
- dict->bd_hf.hf_listen = 1;
- dict->bd_hf.hf_channel = channel;
return 0;
}
-
-/*
- * Parse [additional] protocol descriptor list for L2CAP PSM
- *
- * seq8 len8 2
- * seq8 len8 2
- * uuid16 value16 3 L2CAP
- * uint16 value16 3 PSM
- * seq8 len8 2
- * uuid16 value16 3 HID Protocol
- * ===
- * 15
- */
-
-static int32_t
-parse_l2cap_psm(sdp_attr_t *a)
-{
- uint8_t *ptr = a->value;
- uint8_t *end = a->value + a->vlen;
- int32_t type, len, uuid, psm;
-
- if (end - ptr < 15)
- return (-1);
-
- if (a->attr == SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS) {
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_SEQ8:
- SDP_GET8(len, ptr);
- break;
-
- case SDP_DATA_SEQ16:
- SDP_GET16(len, ptr);
- break;
-
- case SDP_DATA_SEQ32:
- SDP_GET32(len, ptr);
- break;
-
- default:
- return (-1);
- }
- if (ptr + len > end)
- return (-1);
- }
-
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_SEQ8:
- SDP_GET8(len, ptr);
- break;
-
- case SDP_DATA_SEQ16:
- SDP_GET16(len, ptr);
- break;
-
- case SDP_DATA_SEQ32:
- SDP_GET32(len, ptr);
- break;
-
- default:
- return (-1);
- }
- if (ptr + len > end)
- return (-1);
-
- /* Protocol */
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_SEQ8:
- SDP_GET8(len, ptr);
- break;
-
- case SDP_DATA_SEQ16:
- SDP_GET16(len, ptr);
- break;
-
- case SDP_DATA_SEQ32:
- SDP_GET32(len, ptr);
- break;
-
- default:
- return (-1);
- }
- if (ptr + len > end)
- return (-1);
-
- /* UUID */
- if (ptr + 3 > end)
- return (-1);
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_UUID16:
- SDP_GET16(uuid, ptr);
- if (uuid != SDP_UUID_PROTOCOL_L2CAP)
- return (-1);
- break;
-
- case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
- case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
- default:
- return (-1);
- }
-
- /* PSM */
- if (ptr + 3 > end)
- return (-1);
- SDP_GET8(type, ptr);
- if (type != SDP_DATA_UINT16)
- return (-1);
- SDP_GET16(psm, ptr);
-
- return (psm);
-}
-
-/*
- * Parse HID descriptor string
- *
- * seq8 len8 2
- * seq8 len8 2
- * uint8 value8 2
- * str value 3
- * ===
- * 9
- */
-
-static int32_t
-parse_hid_descriptor(sdp_attr_t *a)
-{
- uint8_t *ptr = a->value;
- uint8_t *end = a->value + a->vlen;
- int32_t type, len, descriptor_type;
-
- if (end - ptr < 9)
- return (-1);
-
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_SEQ8:
- SDP_GET8(len, ptr);
- break;
-
- case SDP_DATA_SEQ16:
- SDP_GET16(len, ptr);
- break;
-
- case SDP_DATA_SEQ32:
- SDP_GET32(len, ptr);
- break;
-
- default:
- return (-1);
- }
- if (ptr + len > end)
- return (-1);
-
- while (ptr < end) {
- /* Descriptor */
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_SEQ8:
- if (ptr + 1 > end)
- return (-1);
- SDP_GET8(len, ptr);
- break;
-
- case SDP_DATA_SEQ16:
- if (ptr + 2 > end)
- return (-1);
- SDP_GET16(len, ptr);
- break;
-
- case SDP_DATA_SEQ32:
- if (ptr + 4 > end)
- return (-1);
- SDP_GET32(len, ptr);
- break;
-
- default:
- return (-1);
- }
-
- /* Descripor type */
- if (ptr + 1 > end)
- return (-1);
- SDP_GET8(type, ptr);
- if (type != SDP_DATA_UINT8 || ptr + 1 > end)
- return (-1);
- SDP_GET8(descriptor_type, ptr);
-
- /* Descriptor value */
- if (ptr + 1 > end)
- return (-1);
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_STR8:
- if (ptr + 1 > end)
- return (-1);
- SDP_GET8(len, ptr);
- break;
-
- case SDP_DATA_STR16:
- if (ptr + 2 > end)
- return (-1);
- SDP_GET16(len, ptr);
- break;
-
- case SDP_DATA_STR32:
- if (ptr + 4 > end)
- return (-1);
- SDP_GET32(len, ptr);
- break;
-
- default:
- return (-1);
- }
- if (ptr + len > end)
- return (-1);
-
- if (descriptor_type == UDESC_REPORT && len > 0) {
- a->value = ptr;
- a->vlen = len;
-
- return (0);
- }
-
- ptr += len;
- }
-
- return (-1);
-}
-
-/*
- * Parse boolean value
- *
- * bool8 int8
- */
-
-static int32_t
-parse_boolean(sdp_attr_t *a)
-{
- if (a->vlen != 2 || a->value[0] != SDP_DATA_BOOL)
- return (-1);
-
- return (a->value[1]);
-}
-
-/*
- * Parse protocol descriptor list for the RFCOMM channel
- *
- * seq8 len8 2
- * seq8 len8 2
- * uuid16 value16 3 L2CAP
- * seq8 len8 2
- * uuid16 value16 3 RFCOMM
- * uint8 value8 2 channel
- * ===
- * 14
- */
-
-static int32_t
-parse_rfcomm_channel(sdp_attr_t *a)
-{
- uint8_t *ptr = a->value;
- uint8_t *end = a->value + a->vlen;
- int32_t type, len, uuid, channel;
-
- if (end - ptr < 14)
- return (-1);
-
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_SEQ8:
- SDP_GET8(len, ptr);
- break;
-
- case SDP_DATA_SEQ16:
- SDP_GET16(len, ptr);
- break;
-
- case SDP_DATA_SEQ32:
- SDP_GET32(len, ptr);
- break;
-
- default:
- return (-1);
- }
- if (ptr + len > end)
- return (-1);
-
- /* Protocol */
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_SEQ8:
- SDP_GET8(len, ptr);
- break;
-
- case SDP_DATA_SEQ16:
- SDP_GET16(len, ptr);
- break;
-
- case SDP_DATA_SEQ32:
- SDP_GET32(len, ptr);
- break;
-
- default:
- return (-1);
- }
- if (ptr + len > end)
- return (-1);
-
- /* UUID */
- if (ptr + 3 > end)
- return (-1);
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_UUID16:
- SDP_GET16(uuid, ptr);
- if (uuid != SDP_UUID_PROTOCOL_L2CAP)
- return (-1);
- break;
-
- case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
- case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
- default:
- return (-1);
- }
-
- /* Protocol */
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_SEQ8:
- SDP_GET8(len, ptr);
- break;
-
- case SDP_DATA_SEQ16:
- SDP_GET16(len, ptr);
- break;
-
- case SDP_DATA_SEQ32:
- SDP_GET32(len, ptr);
- break;
-
- default:
- return (-1);
- }
- if (ptr + len > end)
- return (-1);
-
- /* UUID */
- if (ptr + 3 > end)
- return (-1);
- SDP_GET8(type, ptr);
- switch (type) {
- case SDP_DATA_UUID16:
- SDP_GET16(uuid, ptr);
- if (uuid != SDP_UUID_PROTOCOL_RFCOMM)
- return (-1);
- break;
-
- case SDP_DATA_UUID32: /* XXX FIXME can we have 32-bit UUID */
- case SDP_DATA_UUID128: /* XXX FIXME can we have 128-bit UUID */
- default:
- return (-1);
- }
-
- /* channel */
- if (ptr + 2 > end)
- return (-1);
-
- SDP_GET8(type, ptr);
- if (type != SDP_DATA_UINT8)
- return (-1);
-
- SDP_GET8(channel, ptr);
-
- return (channel);
-}
-
-/*
- * return appropriate mode for HID descriptor
- */
-static int
-hid_mode(uint8_t *desc, int32_t dlen)
-{
- report_desc_t r;
- hid_data_t d;
- struct hid_item h;
- int mode;
-
- mode = BTDEV_MODE_AUTH; /* default */
-
- r = hid_use_report_desc(desc, dlen);
- if (r == NULL)
- err(EXIT_FAILURE, "hid_use_report_desc");
-
- d = hid_start_parse(r, ~0, -1);
- while (hid_get_item(d, &h) > 0) {
- if (h.kind == hid_collection
- && HID_PAGE(h.usage) == HUP_GENERIC_DESKTOP
- && HID_USAGE(h.usage) == HUG_KEYBOARD)
- mode = BTDEV_MODE_ENCRYPT;
- }
-
- hid_end_parse(d);
- hid_dispose_report_desc(r);
-
- return mode;
-}