diff options
author | 2008-11-26 15:32:56 +0000 | |
---|---|---|
committer | 2008-11-26 15:32:56 +0000 | |
commit | aa9ef95f93fcf03f4691e00df56d3a2f890d0dd3 (patch) | |
tree | fabccd2ddc3bbd97ff5cf17e10c6b2b5a008702b | |
parent | Add my copyright here, too. (diff) | |
download | wireguard-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/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/btd/bt.c | 214 | ||||
-rw-r--r-- | usr.sbin/btd/btd.c | 81 | ||||
-rw-r--r-- | usr.sbin/btd/btd.h | 19 | ||||
-rw-r--r-- | usr.sbin/btd/conf.c | 7 | ||||
-rw-r--r-- | usr.sbin/btd/hci.c | 35 | ||||
-rw-r--r-- | usr.sbin/btd/sdp.c | 738 |
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; -} |