diff options
-rw-r--r-- | Makefile.objs | 2 | ||||
-rw-r--r-- | bt-host.c | 198 | ||||
-rw-r--r-- | bt-vhci.c | 167 | ||||
-rwxr-xr-x | configure | 31 | ||||
-rw-r--r-- | hw/Kconfig | 1 | ||||
-rw-r--r-- | hw/Makefile.objs | 1 | ||||
-rw-r--r-- | hw/bt/Kconfig | 2 | ||||
-rw-r--r-- | hw/bt/Makefile.objs | 3 | ||||
-rw-r--r-- | hw/bt/core.c | 143 | ||||
-rw-r--r-- | hw/bt/hci-csr.c | 512 | ||||
-rw-r--r-- | hw/bt/hci.c | 2263 | ||||
-rw-r--r-- | hw/bt/hid.c | 553 | ||||
-rw-r--r-- | hw/bt/l2cap.c | 1367 | ||||
-rw-r--r-- | hw/bt/sdp.c | 989 | ||||
-rw-r--r-- | include/hw/bt.h | 2177 | ||||
-rw-r--r-- | include/sysemu/bt.h | 20 | ||||
-rw-r--r-- | qemu-deprecated.texi | 7 | ||||
-rw-r--r-- | qemu-options.hx | 79 | ||||
-rw-r--r-- | vl.c | 136 |
19 files changed, 0 insertions, 8651 deletions
diff --git a/Makefile.objs b/Makefile.objs index 11ba1a36bd..4e4d6ddbb3 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -65,8 +65,6 @@ common-obj-y += replay/ common-obj-y += ui/ common-obj-m += ui/ -common-obj-y += bt-host.o bt-vhci.o -bt-host.o-cflags := $(BLUEZ_CFLAGS) common-obj-y += dma-helpers.o common-obj-y += vl.o diff --git a/bt-host.c b/bt-host.c deleted file mode 100644 index 2f8f631c25..0000000000 --- a/bt-host.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Wrap a host Bluetooth HCI socket in a struct HCIInfo. - * - * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "sysemu/bt.h" -#include "qemu/main-loop.h" - -#ifndef _WIN32 -# include <sys/ioctl.h> -# include <sys/uio.h> -# ifdef CONFIG_BLUEZ -# include <bluetooth/bluetooth.h> -# include <bluetooth/hci.h> -# include <bluetooth/hci_lib.h> -# else -# include "hw/bt.h" -# define HCI_MAX_FRAME_SIZE 1028 -# endif - -struct bt_host_hci_s { - struct HCIInfo hci; - int fd; - - uint8_t hdr[HCI_MAX_FRAME_SIZE]; - int len; -}; - -static void bt_host_send(struct HCIInfo *hci, - int type, const uint8_t *data, int len) -{ - struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci; - uint8_t pkt = type; - struct iovec iv[2]; - - iv[0].iov_base = (void *)&pkt; - iv[0].iov_len = 1; - iv[1].iov_base = (void *) data; - iv[1].iov_len = len; - - while (writev(s->fd, iv, 2) < 0) { - if (errno != EAGAIN && errno != EINTR) { - fprintf(stderr, "qemu: error %i writing bluetooth packet.\n", - errno); - return; - } - } -} - -static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len) -{ - bt_host_send(hci, HCI_COMMAND_PKT, data, len); -} - -static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len) -{ - bt_host_send(hci, HCI_ACLDATA_PKT, data, len); -} - -static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len) -{ - bt_host_send(hci, HCI_SCODATA_PKT, data, len); -} - -static void bt_host_read(void *opaque) -{ - struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque; - uint8_t *pkt; - int pktlen; - - /* Seems that we can't read only the header first and then the amount - * of data indicated in the header because Linux will discard everything - * that's not been read in one go. */ - s->len = read(s->fd, s->hdr, sizeof(s->hdr)); - - if (s->len < 0) { - fprintf(stderr, "qemu: error %i reading HCI frame\n", errno); - return; - } - - pkt = s->hdr; - while (s->len --) - switch (*pkt ++) { - case HCI_EVENT_PKT: - if (s->len < 2) - goto bad_pkt; - - pktlen = MIN(pkt[1] + 2, s->len); - s->hci.evt_recv(s->hci.opaque, pkt, pktlen); - s->len -= pktlen; - pkt += pktlen; - - /* TODO: if this is an Inquiry Result event, it's also - * interpreted by Linux kernel before we received it, possibly - * we should clean the kernel Inquiry cache through - * ioctl(s->fd, HCI_INQUIRY, ...). */ - break; - - case HCI_ACLDATA_PKT: - if (s->len < 4) - goto bad_pkt; - - pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len); - s->hci.acl_recv(s->hci.opaque, pkt, pktlen); - s->len -= pktlen; - pkt += pktlen; - break; - - case HCI_SCODATA_PKT: - if (s->len < 3) - goto bad_pkt; - - pktlen = MIN(pkt[2] + 3, s->len); - s->len -= pktlen; - pkt += pktlen; - break; - - default: - bad_pkt: - fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]); - } -} - -static int bt_host_bdaddr_set(struct HCIInfo *hci, const uint8_t *bd_addr) -{ - return -ENOTSUP; -} - -struct HCIInfo *bt_host_hci(const char *id) -{ - struct bt_host_hci_s *s; - int fd = -1; -# ifdef CONFIG_BLUEZ - int dev_id = hci_devid(id); - struct hci_filter flt; - - if (dev_id < 0) { - fprintf(stderr, "qemu: `%s' not available\n", id); - return 0; - } - - fd = hci_open_dev(dev_id); - - /* XXX: can we ensure nobody else has the device opened? */ -# endif - - if (fd < 0) { - fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n", - id, strerror(errno), errno); - return NULL; - } - -# ifdef CONFIG_BLUEZ - hci_filter_clear(&flt); - hci_filter_all_ptypes(&flt); - hci_filter_all_events(&flt); - - if (qemu_setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { - fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno); - return 0; - } -# endif - - s = g_malloc0(sizeof(struct bt_host_hci_s)); - s->fd = fd; - s->hci.cmd_send = bt_host_cmd; - s->hci.sco_send = bt_host_sco; - s->hci.acl_send = bt_host_acl; - s->hci.bdaddr_set = bt_host_bdaddr_set; - - qemu_set_fd_handler(s->fd, bt_host_read, NULL, s); - - return &s->hci; -} -#else -struct HCIInfo *bt_host_hci(const char *id) -{ - fprintf(stderr, "qemu: bluetooth passthrough not supported (yet)\n"); - - return 0; -} -#endif diff --git a/bt-vhci.c b/bt-vhci.c deleted file mode 100644 index 886e146743..0000000000 --- a/bt-vhci.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Support for host VHCIs inside qemu scatternets. - * - * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "sysemu/bt.h" -#include "hw/bt.h" -#include "qemu/main-loop.h" - -#define VHCI_DEV "/dev/vhci" -#define VHCI_UDEV "/dev/hci_vhci" - -struct bt_vhci_s { - int fd; - struct HCIInfo *info; - - uint8_t hdr[4096]; - int len; -}; - -static void vhci_read(void *opaque) -{ - struct bt_vhci_s *s = (struct bt_vhci_s *) opaque; - uint8_t *pkt; - int pktlen; - - /* Seems that we can't read only the header first and then the amount - * of data indicated in the header because Linux will discard everything - * that's not been read in one go. */ - s->len = read(s->fd, s->hdr, sizeof(s->hdr)); - - if (s->len < 0) { - fprintf(stderr, "qemu: error %i reading the PDU\n", errno); - return; - } - - pkt = s->hdr; - while (s->len --) - switch (*pkt ++) { - case HCI_COMMAND_PKT: - if (s->len < 3) - goto bad_pkt; - - pktlen = MIN(pkt[2] + 3, s->len); - s->info->cmd_send(s->info, pkt, pktlen); - s->len -= pktlen; - pkt += pktlen; - break; - - case HCI_ACLDATA_PKT: - if (s->len < 4) - goto bad_pkt; - - pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len); - s->info->acl_send(s->info, pkt, pktlen); - s->len -= pktlen; - pkt += pktlen; - break; - - case HCI_SCODATA_PKT: - if (s->len < 3) - goto bad_pkt; - - pktlen = MIN(pkt[2] + 3, s->len); - s->info->sco_send(s->info, pkt, pktlen); - s->len -= pktlen; - pkt += pktlen; - break; - - default: - bad_pkt: - fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]); - } -} - -static void vhci_host_send(void *opaque, - int type, const uint8_t *data, int len) -{ - struct bt_vhci_s *s = (struct bt_vhci_s *) opaque; -#if 0 - uint8_t pkt = type; - struct iovec iv[2]; - - iv[0].iov_base = &pkt; - iv[0].iov_len = 1; - iv[1].iov_base = (void *) data; - iv[1].iov_len = len; - - while (writev(s->fd, iv, 2) < 0) - if (errno != EAGAIN && errno != EINTR) { - fprintf(stderr, "qemu: error %i writing bluetooth packet.\n", - errno); - return; - } -#else - /* Apparently VHCI wants us to write everything in one chunk :-( */ - static uint8_t buf[4096]; - - buf[0] = type; - memcpy(buf + 1, data, len); - - while (write(s->fd, buf, len + 1) < 0) - if (errno != EAGAIN && errno != EINTR) { - fprintf(stderr, "qemu: error %i writing bluetooth packet.\n", - errno); - return; - } -#endif -} - -static void vhci_out_hci_packet_event(void *opaque, - const uint8_t *data, int len) -{ - vhci_host_send(opaque, HCI_EVENT_PKT, data, len); -} - -static void vhci_out_hci_packet_acl(void *opaque, - const uint8_t *data, int len) -{ - vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len); -} - -void bt_vhci_init(struct HCIInfo *info) -{ - struct bt_vhci_s *s; - int err[2]; - int fd; - - fd = open(VHCI_DEV, O_RDWR); - err[0] = errno; - if (fd < 0) { - fd = open(VHCI_UDEV, O_RDWR); - err[1] = errno; - } - - if (fd < 0) { - fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n", - VHCI_DEV, strerror(err[0]), err[0]); - fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n", - VHCI_UDEV, strerror(err[1]), err[1]); - exit(-1); - } - - s = g_malloc0(sizeof(struct bt_vhci_s)); - s->fd = fd; - s->info = info ?: qemu_next_hci(); - s->info->opaque = s; - s->info->evt_recv = vhci_out_hci_packet_event; - s->info->acl_recv = vhci_out_hci_packet_acl; - - qemu_set_fd_handler(s->fd, vhci_read, NULL, s); -} @@ -349,7 +349,6 @@ unset target_list_exclude # Distributions want to ensure that several features are compiled in, and it # is impossible without a --enable-foo that exits if a feature is not found. -bluez="" brlapi="" curl="" curses="" @@ -1151,10 +1150,6 @@ for opt do ;; --enable-brlapi) brlapi="yes" ;; - --disable-bluez) bluez="no" - ;; - --enable-bluez) bluez="yes" - ;; --disable-kvm) kvm="no" ;; --enable-kvm) kvm="yes" @@ -1762,7 +1757,6 @@ disabled with --disable-FEATURE, default is enabled if available: curl curl connectivity membarrier membarrier system call (for Linux 4.14+ or Windows) fdt fdt device tree - bluez bluez stack connectivity kvm KVM acceleration support hax HAX acceleration support hvf Hypervisor.framework acceleration support @@ -3666,26 +3660,6 @@ EOF fi # test "$curl" ########################################## -# bluez support probe -if test "$bluez" != "no" ; then - cat > $TMPC << EOF -#include <bluetooth/bluetooth.h> -int main(void) { return bt_error(0); } -EOF - bluez_cflags=$($pkg_config --cflags bluez 2>/dev/null) - bluez_libs=$($pkg_config --libs bluez 2>/dev/null) - if compile_prog "$bluez_cflags" "$bluez_libs" ; then - bluez=yes - libs_softmmu="$bluez_libs $libs_softmmu" - else - if test "$bluez" = "yes" ; then - feature_not_found "bluez" "Install bluez-libs/libbluetooth devel" - fi - bluez="no" - fi -fi - -########################################## # glib support probe glib_req_ver=2.48 @@ -6493,7 +6467,6 @@ if test "$xen" = "yes" ; then echo "xen ctrl version $xen_ctrl_version" fi echo "brlapi support $brlapi" -echo "bluez support $bluez" echo "Documentation $docs" echo "PIE $pie" echo "vde support $vde" @@ -6917,10 +6890,6 @@ if test "$brlapi" = "yes" ; then echo "CONFIG_BRLAPI=y" >> $config_host_mak echo "BRLAPI_LIBS=$brlapi_libs" >> $config_host_mak fi -if test "$bluez" = "yes" ; then - echo "CONFIG_BLUEZ=y" >> $config_host_mak - echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak -fi if test "$gtk" = "yes" ; then echo "CONFIG_GTK=m" >> $config_host_mak echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak diff --git a/hw/Kconfig b/hw/Kconfig index b9685b3944..ecf491bf04 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -4,7 +4,6 @@ source acpi/Kconfig source adc/Kconfig source audio/Kconfig source block/Kconfig -source bt/Kconfig source char/Kconfig source core/Kconfig source display/Kconfig diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 66eef20561..660e2b4373 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -5,7 +5,6 @@ devices-dirs-y += acpi/ devices-dirs-y += adc/ devices-dirs-y += audio/ devices-dirs-y += block/ -devices-dirs-y += bt/ devices-dirs-y += char/ devices-dirs-y += cpu/ devices-dirs-y += display/ diff --git a/hw/bt/Kconfig b/hw/bt/Kconfig index 554a9ee75e..e69de29bb2 100644 --- a/hw/bt/Kconfig +++ b/hw/bt/Kconfig @@ -1,2 +0,0 @@ -config BLUETOOTH - bool diff --git a/hw/bt/Makefile.objs b/hw/bt/Makefile.objs deleted file mode 100644 index 867a7d2e8a..0000000000 --- a/hw/bt/Makefile.objs +++ /dev/null @@ -1,3 +0,0 @@ -common-obj-y += core.o l2cap.o sdp.o hci.o hid.o -common-obj-y += hci-csr.o - diff --git a/hw/bt/core.c b/hw/bt/core.c deleted file mode 100644 index dfb196e2a4..0000000000 --- a/hw/bt/core.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Convenience functions for bluetooth. - * - * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "sysemu/bt.h" -#include "hw/bt.h" - -/* Slave implementations can ignore this */ -static void bt_dummy_lmp_mode_change(struct bt_link_s *link) -{ -} - -/* Slaves should never receive these PDUs */ -static void bt_dummy_lmp_connection_complete(struct bt_link_s *link) -{ - if (link->slave->reject_reason) - error_report("%s: stray LMP_not_accepted received, fixme", __func__); - else - error_report("%s: stray LMP_accepted received, fixme", __func__); - exit(-1); -} - -static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link) -{ - error_report("%s: stray LMP_detach received, fixme", __func__); - exit(-1); -} - -static void bt_dummy_lmp_acl_resp(struct bt_link_s *link, - const uint8_t *data, int start, int len) -{ - error_report("%s: stray ACL response PDU, fixme", __func__); - exit(-1); -} - -/* Slaves that don't hold any additional per link state can use these */ -static void bt_dummy_lmp_connection_request(struct bt_link_s *req) -{ - struct bt_link_s *link = g_malloc0(sizeof(struct bt_link_s)); - - link->slave = req->slave; - link->host = req->host; - - req->host->reject_reason = 0; - req->host->lmp_connection_complete(link); -} - -static void bt_dummy_lmp_disconnect_slave(struct bt_link_s *link) -{ - g_free(link); -} - -static void bt_dummy_destroy(struct bt_device_s *device) -{ - bt_device_done(device); - g_free(device); -} - -static int bt_dev_idx = 0; - -void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net) -{ - memset(dev, 0, sizeof(*dev)); - dev->inquiry_scan = 1; - dev->page_scan = 1; - - dev->bd_addr.b[0] = bt_dev_idx & 0xff; - dev->bd_addr.b[1] = bt_dev_idx >> 8; - dev->bd_addr.b[2] = 0xd0; - dev->bd_addr.b[3] = 0xba; - dev->bd_addr.b[4] = 0xbe; - dev->bd_addr.b[5] = 0xba; - bt_dev_idx ++; - - /* Simple slave-only devices need to implement only .lmp_acl_data */ - dev->lmp_connection_complete = bt_dummy_lmp_connection_complete; - dev->lmp_disconnect_master = bt_dummy_lmp_disconnect_master; - dev->lmp_acl_resp = bt_dummy_lmp_acl_resp; - dev->lmp_mode_change = bt_dummy_lmp_mode_change; - dev->lmp_connection_request = bt_dummy_lmp_connection_request; - dev->lmp_disconnect_slave = bt_dummy_lmp_disconnect_slave; - - dev->handle_destroy = bt_dummy_destroy; - - dev->net = net; - dev->next = net->slave; - net->slave = dev; -} - -void bt_device_done(struct bt_device_s *dev) -{ - struct bt_device_s **p = &dev->net->slave; - - while (*p && *p != dev) - p = &(*p)->next; - if (*p != dev) { - error_report("%s: bad bt device \"%s\"", __func__, - dev->lmp_name ?: "(null)"); - exit(-1); - } - - *p = dev->next; -} - -static struct bt_vlan_s { - struct bt_scatternet_s net; - int id; - struct bt_vlan_s *next; -} *first_bt_vlan; - -/* find or alloc a new bluetooth "VLAN" */ -struct bt_scatternet_s *qemu_find_bt_vlan(int id) -{ - struct bt_vlan_s **pvlan, *vlan; - for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) { - if (vlan->id == id) - return &vlan->net; - } - vlan = g_malloc0(sizeof(struct bt_vlan_s)); - vlan->id = id; - pvlan = &first_bt_vlan; - while (*pvlan != NULL) - pvlan = &(*pvlan)->next; - *pvlan = vlan; - return &vlan->net; -} diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c deleted file mode 100644 index 3d60654f44..0000000000 --- a/hw/bt/hci-csr.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Bluetooth serial HCI transport. - * CSR41814 HCI with H4p vendor extensions. - * - * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "chardev/char-serial.h" -#include "qemu/timer.h" -#include "qemu/bswap.h" -#include "hw/irq.h" -#include "sysemu/bt.h" -#include "hw/bt.h" -#include "qapi/error.h" - -struct csrhci_s { - Chardev parent; - int enable; - qemu_irq *pins; - int pin_state; - int modem_state; -#define FIFO_LEN 4096 - int out_start; - int out_len; - int out_size; - uint8_t outfifo[FIFO_LEN * 2]; - uint8_t inpkt[FIFO_LEN]; - enum { - CSR_HDR_LEN, - CSR_DATA_LEN, - CSR_DATA - } in_state; - int in_len; - int in_hdr; - int in_needed; - QEMUTimer *out_tm; - int64_t baud_delay; - - bdaddr_t bd_addr; - struct HCIInfo *hci; -}; - -#define TYPE_CHARDEV_HCI "chardev-hci" -#define HCI_CHARDEV(obj) OBJECT_CHECK(struct csrhci_s, (obj), TYPE_CHARDEV_HCI) - -/* H4+ packet types */ -enum { - H4_CMD_PKT = 1, - H4_ACL_PKT = 2, - H4_SCO_PKT = 3, - H4_EVT_PKT = 4, - H4_NEG_PKT = 6, - H4_ALIVE_PKT = 7, -}; - -/* CSR41814 negotiation start magic packet */ -static const uint8_t csrhci_neg_packet[] = { - H4_NEG_PKT, 10, - 0x00, 0xa0, 0x01, 0x00, 0x00, - 0x4c, 0x00, 0x96, 0x00, 0x00, -}; - -/* CSR41814 vendor-specific command OCFs */ -enum { - OCF_CSR_SEND_FIRMWARE = 0x000, -}; - -static inline void csrhci_fifo_wake(struct csrhci_s *s) -{ - Chardev *chr = CHARDEV(s); - - if (!s->enable || !s->out_len) - return; - - /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */ - if (qemu_chr_be_can_write(chr)) { - qemu_chr_be_write(chr, s->outfifo + s->out_start++, 1); - s->out_len--; - if (s->out_start >= s->out_size) { - s->out_start = 0; - s->out_size = FIFO_LEN; - } - } - - if (s->out_len) - timer_mod(s->out_tm, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->baud_delay); -} - -#define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len) -static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len) -{ - int off = s->out_start + s->out_len; - - /* TODO: do the padding here, i.e. align len */ - s->out_len += len; - - if (off < FIFO_LEN) { - if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) { - error_report("%s: can't alloc %i bytes", __func__, len); - exit(-1); - } - return s->outfifo + off; - } - - if (s->out_len > s->out_size) { - error_report("%s: can't alloc %i bytes", __func__, len); - exit(-1); - } - - return s->outfifo + off - s->out_size; -} - -static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s, - int type, int len) -{ - uint8_t *ret = csrhci_out_packetz(s, len + 2); - - *ret ++ = type; - *ret ++ = len; - - return ret; -} - -static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s, - int evt, int len) -{ - uint8_t *ret = csrhci_out_packetz(s, - len + 1 + sizeof(struct hci_event_hdr)); - - *ret ++ = H4_EVT_PKT; - ((struct hci_event_hdr *) ret)->evt = evt; - ((struct hci_event_hdr *) ret)->plen = len; - - return ret + sizeof(struct hci_event_hdr); -} - -static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf, - uint8_t *data, int len) -{ - int offset; - uint8_t *rpkt; - - switch (ocf) { - case OCF_CSR_SEND_FIRMWARE: - /* Check if this is the bd_address packet */ - if (len >= 18 + 8 && data[12] == 0x01 && data[13] == 0x00) { - offset = 18; - s->bd_addr.b[0] = data[offset + 7]; /* Beyond cmd packet end(!?) */ - s->bd_addr.b[1] = data[offset + 6]; - s->bd_addr.b[2] = data[offset + 4]; - s->bd_addr.b[3] = data[offset + 0]; - s->bd_addr.b[4] = data[offset + 3]; - s->bd_addr.b[5] = data[offset + 2]; - - s->hci->bdaddr_set(s->hci, s->bd_addr.b); - error_report("%s: bd_address loaded from firmware: " - "%02x:%02x:%02x:%02x:%02x:%02x", __func__, - s->bd_addr.b[0], s->bd_addr.b[1], s->bd_addr.b[2], - s->bd_addr.b[3], s->bd_addr.b[4], s->bd_addr.b[5]); - } - - rpkt = csrhci_out_packet_event(s, EVT_VENDOR, 11); - /* Status bytes: no error */ - rpkt[9] = 0x00; - rpkt[10] = 0x00; - break; - - default: - error_report("%s: got a bad CMD packet", __func__); - return; - } - - csrhci_fifo_wake(s); -} - -static void csrhci_in_packet(struct csrhci_s *s, uint8_t *pkt) -{ - uint8_t *rpkt; - int opc; - - switch (*pkt ++) { - case H4_CMD_PKT: - opc = le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode); - if (cmd_opcode_ogf(opc) == OGF_VENDOR_CMD) { - csrhci_in_packet_vendor(s, cmd_opcode_ocf(opc), - pkt + sizeof(struct hci_command_hdr), - s->in_len - sizeof(struct hci_command_hdr) - 1); - return; - } - - /* TODO: if the command is OCF_READ_LOCAL_COMMANDS or the likes, - * we need to send it to the HCI layer and then add our supported - * commands to the returned mask (such as OGF_VENDOR_CMD). With - * bt-hci.c we could just have hooks for this kind of commands but - * we can't with bt-host.c. */ - - s->hci->cmd_send(s->hci, pkt, s->in_len - 1); - break; - - case H4_EVT_PKT: - goto bad_pkt; - - case H4_ACL_PKT: - s->hci->acl_send(s->hci, pkt, s->in_len - 1); - break; - - case H4_SCO_PKT: - s->hci->sco_send(s->hci, pkt, s->in_len - 1); - break; - - case H4_NEG_PKT: - if (s->in_hdr != sizeof(csrhci_neg_packet) || - memcmp(pkt - 1, csrhci_neg_packet, s->in_hdr)) { - error_report("%s: got a bad NEG packet", __func__); - return; - } - pkt += 2; - - rpkt = csrhci_out_packet_csr(s, H4_NEG_PKT, 10); - - *rpkt ++ = 0x20; /* Operational settings negotiation Ok */ - memcpy(rpkt, pkt, 7); rpkt += 7; - *rpkt ++ = 0xff; - *rpkt = 0xff; - break; - - case H4_ALIVE_PKT: - if (s->in_hdr != 4 || pkt[1] != 0x55 || pkt[2] != 0x00) { - error_report("%s: got a bad ALIVE packet", __func__); - return; - } - - rpkt = csrhci_out_packet_csr(s, H4_ALIVE_PKT, 2); - - *rpkt ++ = 0xcc; - *rpkt = 0x00; - break; - - default: - bad_pkt: - /* TODO: error out */ - error_report("%s: got a bad packet", __func__); - break; - } - - csrhci_fifo_wake(s); -} - -static int csrhci_header_len(const uint8_t *pkt) -{ - switch (pkt[0]) { - case H4_CMD_PKT: - return HCI_COMMAND_HDR_SIZE; - case H4_EVT_PKT: - return HCI_EVENT_HDR_SIZE; - case H4_ACL_PKT: - return HCI_ACL_HDR_SIZE; - case H4_SCO_PKT: - return HCI_SCO_HDR_SIZE; - case H4_NEG_PKT: - return pkt[1] + 1; - case H4_ALIVE_PKT: - return 3; - } - - exit(-1); -} - -static int csrhci_data_len(const uint8_t *pkt) -{ - switch (*pkt ++) { - case H4_CMD_PKT: - /* It seems that vendor-specific command packets for H4+ are all - * one byte longer than indicated in the standard header. */ - if (le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode) == 0xfc00) - return (((struct hci_command_hdr *) pkt)->plen + 1) & ~1; - - return ((struct hci_command_hdr *) pkt)->plen; - case H4_EVT_PKT: - return ((struct hci_event_hdr *) pkt)->plen; - case H4_ACL_PKT: - return le16_to_cpu(((struct hci_acl_hdr *) pkt)->dlen); - case H4_SCO_PKT: - return ((struct hci_sco_hdr *) pkt)->dlen; - case H4_NEG_PKT: - case H4_ALIVE_PKT: - return 0; - } - - exit(-1); -} - -static void csrhci_ready_for_next_inpkt(struct csrhci_s *s) -{ - s->in_state = CSR_HDR_LEN; - s->in_len = 0; - s->in_needed = 2; - s->in_hdr = INT_MAX; -} - -static int csrhci_write(struct Chardev *chr, - const uint8_t *buf, int len) -{ - struct csrhci_s *s = (struct csrhci_s *)chr; - int total = 0; - - if (!s->enable) - return 0; - - for (;;) { - int cnt = MIN(len, s->in_needed - s->in_len); - if (cnt) { - memcpy(s->inpkt + s->in_len, buf, cnt); - s->in_len += cnt; - buf += cnt; - len -= cnt; - total += cnt; - } - - if (s->in_len < s->in_needed) { - break; - } - - if (s->in_state == CSR_HDR_LEN) { - s->in_hdr = csrhci_header_len(s->inpkt) + 1; - assert(s->in_hdr >= s->in_needed); - s->in_needed = s->in_hdr; - s->in_state = CSR_DATA_LEN; - continue; - } - - if (s->in_state == CSR_DATA_LEN) { - s->in_needed += csrhci_data_len(s->inpkt); - /* hci_acl_hdr could specify more than 4096 bytes, so assert. */ - assert(s->in_needed <= sizeof(s->inpkt)); - s->in_state = CSR_DATA; - continue; - } - - if (s->in_state == CSR_DATA) { - csrhci_in_packet(s, s->inpkt); - csrhci_ready_for_next_inpkt(s); - } - } - - return total; -} - -static void csrhci_out_hci_packet_event(void *opaque, - const uint8_t *data, int len) -{ - struct csrhci_s *s = (struct csrhci_s *) opaque; - uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */ - - *pkt ++ = H4_EVT_PKT; - memcpy(pkt, data, len); - - csrhci_fifo_wake(s); -} - -static void csrhci_out_hci_packet_acl(void *opaque, - const uint8_t *data, int len) -{ - struct csrhci_s *s = (struct csrhci_s *) opaque; - uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1); /* Align */ - - *pkt ++ = H4_ACL_PKT; - pkt[len & ~1] = 0; - memcpy(pkt, data, len); - - csrhci_fifo_wake(s); -} - -static int csrhci_ioctl(struct Chardev *chr, int cmd, void *arg) -{ - QEMUSerialSetParams *ssp; - struct csrhci_s *s = (struct csrhci_s *) chr; - int prev_state = s->modem_state; - - switch (cmd) { - case CHR_IOCTL_SERIAL_SET_PARAMS: - ssp = (QEMUSerialSetParams *) arg; - s->baud_delay = NANOSECONDS_PER_SECOND / ssp->speed; - /* Moments later... (but shorter than 100ms) */ - s->modem_state |= CHR_TIOCM_CTS; - break; - - case CHR_IOCTL_SERIAL_GET_TIOCM: - *(int *) arg = s->modem_state; - break; - - case CHR_IOCTL_SERIAL_SET_TIOCM: - s->modem_state = *(int *) arg; - if (~s->modem_state & prev_state & CHR_TIOCM_RTS) - s->modem_state &= ~CHR_TIOCM_CTS; - break; - - default: - return -ENOTSUP; - } - return 0; -} - -static void csrhci_reset(struct csrhci_s *s) -{ - s->out_len = 0; - s->out_size = FIFO_LEN; - csrhci_ready_for_next_inpkt(s); - s->baud_delay = NANOSECONDS_PER_SECOND; - s->enable = 0; - - s->modem_state = 0; - /* After a while... (but sooner than 10ms) */ - s->modem_state |= CHR_TIOCM_CTS; - - memset(&s->bd_addr, 0, sizeof(bdaddr_t)); -} - -static void csrhci_out_tick(void *opaque) -{ - csrhci_fifo_wake((struct csrhci_s *) opaque); -} - -static void csrhci_pins(void *opaque, int line, int level) -{ - struct csrhci_s *s = (struct csrhci_s *) opaque; - int state = s->pin_state; - - s->pin_state &= ~(1 << line); - s->pin_state |= (!!level) << line; - - if ((state & ~s->pin_state) & (1 << csrhci_pin_reset)) { - /* TODO: Disappear from lower layers */ - csrhci_reset(s); - } - - if (s->pin_state == 3 && state != 3) { - s->enable = 1; - /* TODO: Wake lower layers up */ - } -} - -qemu_irq *csrhci_pins_get(Chardev *chr) -{ - struct csrhci_s *s = (struct csrhci_s *) chr; - - return s->pins; -} - -static void csrhci_open(Chardev *chr, - ChardevBackend *backend, - bool *be_opened, - Error **errp) -{ - struct csrhci_s *s = HCI_CHARDEV(chr); - - s->hci = qemu_next_hci(); - s->hci->opaque = s; - s->hci->evt_recv = csrhci_out_hci_packet_event; - s->hci->acl_recv = csrhci_out_hci_packet_acl; - - s->out_tm = timer_new_ns(QEMU_CLOCK_VIRTUAL, csrhci_out_tick, s); - s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins); - csrhci_reset(s); - *be_opened = false; -} - -static void char_hci_class_init(ObjectClass *oc, void *data) -{ - ChardevClass *cc = CHARDEV_CLASS(oc); - - cc->internal = true; - cc->open = csrhci_open; - cc->chr_write = csrhci_write; - cc->chr_ioctl = csrhci_ioctl; -} - -static const TypeInfo char_hci_type_info = { - .name = TYPE_CHARDEV_HCI, - .parent = TYPE_CHARDEV, - .instance_size = sizeof(struct csrhci_s), - .class_init = char_hci_class_init, -}; - -Chardev *uart_hci_init(void) -{ - return qemu_chardev_new(NULL, TYPE_CHARDEV_HCI, - NULL, NULL, &error_abort); -} - -static void register_types(void) -{ - type_register_static(&char_hci_type_info); -} - -type_init(register_types); diff --git a/hw/bt/hci.c b/hw/bt/hci.c deleted file mode 100644 index c7958f6c35..0000000000 --- a/hw/bt/hci.c +++ /dev/null @@ -1,2263 +0,0 @@ -/* - * QEMU Bluetooth HCI logic. - * - * Copyright (C) 2007 OpenMoko, Inc. - * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "qapi/error.h" -#include "qemu/timer.h" -#include "hw/usb.h" -#include "sysemu/bt.h" -#include "hw/bt.h" -#include "qapi/qmp/qerror.h" -#include "sysemu/replay.h" -#include "qemu/cutils.h" - -struct bt_hci_s { - uint8_t *(*evt_packet)(void *opaque); - void (*evt_submit)(void *opaque, int len); - void *opaque; - uint8_t evt_buf[256]; - - uint8_t acl_buf[4096]; - int acl_len; - - uint16_t asb_handle; - uint16_t psb_handle; - - int last_cmd; /* Note: Always little-endian */ - - struct bt_device_s *conn_req_host; - - struct { - int inquire; - int periodic; - int responses_left; - int responses; - QEMUTimer *inquiry_done; - QEMUTimer *inquiry_next; - int inquiry_length; - int inquiry_period; - int inquiry_mode; - -#define HCI_HANDLE_OFFSET 0x20 -#define HCI_HANDLES_MAX 0x10 - struct bt_hci_master_link_s { - struct bt_link_s *link; - void (*lmp_acl_data)(struct bt_link_s *link, - const uint8_t *data, int start, int len); - QEMUTimer *acl_mode_timer; - } handle[HCI_HANDLES_MAX]; - uint32_t role_bmp; - int last_handle; - int connecting; - bdaddr_t awaiting_bdaddr[HCI_HANDLES_MAX]; - } lm; - - uint8_t event_mask[8]; - uint16_t voice_setting; /* Notw: Always little-endian */ - uint16_t conn_accept_tout; - QEMUTimer *conn_accept_timer; - - struct HCIInfo info; - struct bt_device_s device; - - Error *replay_blocker; -}; - -#define DEFAULT_RSSI_DBM 20 - -#define hci_from_info(ptr) container_of((ptr), struct bt_hci_s, info) -#define hci_from_device(ptr) container_of((ptr), struct bt_hci_s, device) - -struct bt_hci_link_s { - struct bt_link_s btlink; - uint16_t handle; /* Local */ -}; - -/* LMP layer emulation */ -#if 0 -static void bt_submit_lmp(struct bt_device_s *bt, int length, uint8_t *data) -{ - int resp, resplen, error, op, tr; - uint8_t respdata[17]; - - if (length < 1) - return; - - tr = *data & 1; - op = *(data ++) >> 1; - resp = LMP_ACCEPTED; - resplen = 2; - respdata[1] = op; - error = 0; - length --; - - if (op >= 0x7c) { /* Extended opcode */ - op |= *(data ++) << 8; - resp = LMP_ACCEPTED_EXT; - resplen = 4; - respdata[0] = op >> 8; - respdata[1] = op & 0xff; - length --; - } - - switch (op) { - case LMP_ACCEPTED: - /* data[0] Op code - */ - if (length < 1) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - resp = 0; - break; - - case LMP_ACCEPTED_EXT: - /* data[0] Escape op code - * data[1] Extended op code - */ - if (length < 2) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - resp = 0; - break; - - case LMP_NOT_ACCEPTED: - /* data[0] Op code - * data[1] Error code - */ - if (length < 2) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - resp = 0; - break; - - case LMP_NOT_ACCEPTED_EXT: - /* data[0] Op code - * data[1] Extended op code - * data[2] Error code - */ - if (length < 3) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - resp = 0; - break; - - case LMP_HOST_CONNECTION_REQ: - break; - - case LMP_SETUP_COMPLETE: - resp = LMP_SETUP_COMPLETE; - resplen = 1; - bt->setup = 1; - break; - - case LMP_DETACH: - /* data[0] Error code - */ - if (length < 1) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - bt->setup = 0; - resp = 0; - break; - - case LMP_SUPERVISION_TIMEOUT: - /* data[0,1] Supervision timeout - */ - if (length < 2) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - resp = 0; - break; - - case LMP_QUALITY_OF_SERVICE: - resp = 0; - /* Fall through */ - case LMP_QOS_REQ: - /* data[0,1] Poll interval - * data[2] N(BC) - */ - if (length < 3) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - break; - - case LMP_MAX_SLOT: - resp = 0; - /* Fall through */ - case LMP_MAX_SLOT_REQ: - /* data[0] Max slots - */ - if (length < 1) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - break; - - case LMP_AU_RAND: - case LMP_IN_RAND: - case LMP_COMB_KEY: - /* data[0-15] Random number - */ - if (length < 16) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - if (op == LMP_AU_RAND) { - if (bt->key_present) { - resp = LMP_SRES; - resplen = 5; - /* XXX: [Part H] Section 6.1 on page 801 */ - } else { - error = HCI_PIN_OR_KEY_MISSING; - goto not_accepted; - } - } else if (op == LMP_IN_RAND) { - error = HCI_PAIRING_NOT_ALLOWED; - goto not_accepted; - } else { - /* XXX: [Part H] Section 3.2 on page 779 */ - resp = LMP_UNIT_KEY; - resplen = 17; - memcpy(respdata + 1, bt->key, 16); - - error = HCI_UNIT_LINK_KEY_USED; - goto not_accepted; - } - break; - - case LMP_UNIT_KEY: - /* data[0-15] Key - */ - if (length < 16) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - memcpy(bt->key, data, 16); - bt->key_present = 1; - break; - - case LMP_SRES: - /* data[0-3] Authentication response - */ - if (length < 4) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - break; - - case LMP_CLKOFFSET_REQ: - resp = LMP_CLKOFFSET_RES; - resplen = 3; - respdata[1] = 0x33; - respdata[2] = 0x33; - break; - - case LMP_CLKOFFSET_RES: - /* data[0,1] Clock offset - * (Slave to master only) - */ - if (length < 2) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - break; - - case LMP_VERSION_REQ: - case LMP_VERSION_RES: - /* data[0] VersNr - * data[1,2] CompId - * data[3,4] SubVersNr - */ - if (length < 5) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - if (op == LMP_VERSION_REQ) { - resp = LMP_VERSION_RES; - resplen = 6; - respdata[1] = 0x20; - respdata[2] = 0xff; - respdata[3] = 0xff; - respdata[4] = 0xff; - respdata[5] = 0xff; - } else - resp = 0; - break; - - case LMP_FEATURES_REQ: - case LMP_FEATURES_RES: - /* data[0-7] Features - */ - if (length < 8) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - if (op == LMP_FEATURES_REQ) { - resp = LMP_FEATURES_RES; - resplen = 9; - respdata[1] = (bt->lmp_caps >> 0) & 0xff; - respdata[2] = (bt->lmp_caps >> 8) & 0xff; - respdata[3] = (bt->lmp_caps >> 16) & 0xff; - respdata[4] = (bt->lmp_caps >> 24) & 0xff; - respdata[5] = (bt->lmp_caps >> 32) & 0xff; - respdata[6] = (bt->lmp_caps >> 40) & 0xff; - respdata[7] = (bt->lmp_caps >> 48) & 0xff; - respdata[8] = (bt->lmp_caps >> 56) & 0xff; - } else - resp = 0; - break; - - case LMP_NAME_REQ: - /* data[0] Name offset - */ - if (length < 1) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - resp = LMP_NAME_RES; - resplen = 17; - respdata[1] = data[0]; - respdata[2] = strlen(bt->lmp_name); - memset(respdata + 3, 0x00, 14); - if (respdata[2] > respdata[1]) - memcpy(respdata + 3, bt->lmp_name + respdata[1], - respdata[2] - respdata[1]); - break; - - case LMP_NAME_RES: - /* data[0] Name offset - * data[1] Name length - * data[2-15] Name fragment - */ - if (length < 16) { - error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; - goto not_accepted; - } - resp = 0; - break; - - default: - error = HCI_UNKNOWN_LMP_PDU; - /* Fall through */ - not_accepted: - if (op >> 8) { - resp = LMP_NOT_ACCEPTED_EXT; - resplen = 5; - respdata[0] = op >> 8; - respdata[1] = op & 0xff; - respdata[2] = error; - } else { - resp = LMP_NOT_ACCEPTED; - resplen = 3; - respdata[0] = op & 0xff; - respdata[1] = error; - } - } - - if (resp == 0) - return; - - if (resp >> 8) { - respdata[0] = resp >> 8; - respdata[1] = resp & 0xff; - } else - respdata[0] = resp & 0xff; - - respdata[0] <<= 1; - respdata[0] |= tr; -} - -static void bt_submit_raw_acl(struct bt_piconet_s *net, int length, uint8_t *data) -{ - struct bt_device_s *slave; - if (length < 1) - return; - - slave = 0; -#if 0 - slave = net->slave; -#endif - - switch (data[0] & 3) { - case LLID_ACLC: - bt_submit_lmp(slave, length - 1, data + 1); - break; - case LLID_ACLU_START: -#if 0 - bt_sumbit_l2cap(slave, length - 1, data + 1, (data[0] >> 2) & 1); - breka; -#endif - default: - case LLID_ACLU_CONT: - break; - } -} -#endif - -/* HCI layer emulation */ - -/* Note: we could ignore endianness because unswapped handles will still - * be valid as connection identifiers for the guest - they don't have to - * be continuously allocated. We do it though, to preserve similar - * behaviour between hosts. Some things, like the BD_ADDR cannot be - * preserved though (for example if a real hci is used). */ -#define HNDL(raw) cpu_to_le16(raw) - -static const uint8_t bt_event_reserved_mask[8] = { - 0xff, 0x9f, 0xfb, 0xff, 0x07, 0x18, 0x00, 0x00, -}; - - -static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len) -{ -} - -static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr) -{ - return -ENOTSUP; -} - -struct HCIInfo null_hci = { - .cmd_send = null_hci_send, - .sco_send = null_hci_send, - .acl_send = null_hci_send, - .bdaddr_set = null_hci_addr_set, -}; - - -static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci, - int evt, int len) -{ - uint8_t *packet, mask; - int mask_byte; - - if (len > 255) { - error_report("%s: HCI event params too long (%ib)", __func__, len); - exit(-1); - } - - mask_byte = (evt - 1) >> 3; - mask = 1 << ((evt - 1) & 3); - if (mask & bt_event_reserved_mask[mask_byte] & ~hci->event_mask[mask_byte]) - return NULL; - - packet = hci->evt_packet(hci->opaque); - packet[0] = evt; - packet[1] = len; - - return &packet[2]; -} - -static inline void bt_hci_event(struct bt_hci_s *hci, int evt, - void *params, int len) -{ - uint8_t *packet = bt_hci_event_start(hci, evt, len); - - if (!packet) - return; - - if (len) - memcpy(packet, params, len); - - hci->evt_submit(hci->opaque, len + 2); -} - -static inline void bt_hci_event_status(struct bt_hci_s *hci, int status) -{ - evt_cmd_status params = { - .status = status, - .ncmd = 1, - .opcode = hci->last_cmd, - }; - - bt_hci_event(hci, EVT_CMD_STATUS, ¶ms, EVT_CMD_STATUS_SIZE); -} - -static inline void bt_hci_event_complete(struct bt_hci_s *hci, - void *ret, int len) -{ - uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE, - len + EVT_CMD_COMPLETE_SIZE); - evt_cmd_complete *params = (evt_cmd_complete *) packet; - - if (!packet) - return; - - params->ncmd = 1; - params->opcode = hci->last_cmd; - if (len) - memcpy(&packet[EVT_CMD_COMPLETE_SIZE], ret, len); - - hci->evt_submit(hci->opaque, len + EVT_CMD_COMPLETE_SIZE + 2); -} - -static void bt_hci_inquiry_done(void *opaque) -{ - struct bt_hci_s *hci = (struct bt_hci_s *) opaque; - uint8_t status = HCI_SUCCESS; - - if (!hci->lm.periodic) - hci->lm.inquire = 0; - - /* The specification is inconsistent about this one. Page 565 reads - * "The event parameters of Inquiry Complete event will have a summary - * of the result from the Inquiry process, which reports the number of - * nearby Bluetooth devices that responded [so hci->responses].", but - * Event Parameters (see page 729) has only Status. */ - bt_hci_event(hci, EVT_INQUIRY_COMPLETE, &status, 1); -} - -static void bt_hci_inquiry_result_standard(struct bt_hci_s *hci, - struct bt_device_s *slave) -{ - inquiry_info params = { - .num_responses = 1, - .bdaddr = BAINIT(&slave->bd_addr), - .pscan_rep_mode = 0x00, /* R0 */ - .pscan_period_mode = 0x00, /* P0 - deprecated */ - .pscan_mode = 0x00, /* Standard scan - deprecated */ - .dev_class[0] = slave->class[0], - .dev_class[1] = slave->class[1], - .dev_class[2] = slave->class[2], - /* TODO: return the clkoff *differenece* */ - .clock_offset = slave->clkoff, /* Note: no swapping */ - }; - - bt_hci_event(hci, EVT_INQUIRY_RESULT, ¶ms, INQUIRY_INFO_SIZE); -} - -static void bt_hci_inquiry_result_with_rssi(struct bt_hci_s *hci, - struct bt_device_s *slave) -{ - inquiry_info_with_rssi params = { - .num_responses = 1, - .bdaddr = BAINIT(&slave->bd_addr), - .pscan_rep_mode = 0x00, /* R0 */ - .pscan_period_mode = 0x00, /* P0 - deprecated */ - .dev_class[0] = slave->class[0], - .dev_class[1] = slave->class[1], - .dev_class[2] = slave->class[2], - /* TODO: return the clkoff *differenece* */ - .clock_offset = slave->clkoff, /* Note: no swapping */ - .rssi = DEFAULT_RSSI_DBM, - }; - - bt_hci_event(hci, EVT_INQUIRY_RESULT_WITH_RSSI, - ¶ms, INQUIRY_INFO_WITH_RSSI_SIZE); -} - -static void bt_hci_inquiry_result(struct bt_hci_s *hci, - struct bt_device_s *slave) -{ - if (!slave->inquiry_scan || !hci->lm.responses_left) - return; - - hci->lm.responses_left --; - hci->lm.responses ++; - - switch (hci->lm.inquiry_mode) { - case 0x00: - bt_hci_inquiry_result_standard(hci, slave); - return; - case 0x01: - bt_hci_inquiry_result_with_rssi(hci, slave); - return; - default: - error_report("%s: bad inquiry mode %02x", __func__, - hci->lm.inquiry_mode); - exit(-1); - } -} - -static void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period) -{ - timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - (uint64_t)(period << 7) * 10000000); -} - -static void bt_hci_inquiry_start(struct bt_hci_s *hci, int length) -{ - struct bt_device_s *slave; - - hci->lm.inquiry_length = length; - for (slave = hci->device.net->slave; slave; slave = slave->next) - /* Don't uncover ourselves. */ - if (slave != &hci->device) - bt_hci_inquiry_result(hci, slave); - - /* TODO: register for a callback on a new device's addition to the - * scatternet so that if it's added before inquiry_length expires, - * an Inquiry Result is generated immediately. Alternatively re-loop - * through the devices on the inquiry_length expiration and report - * devices not seen before. */ - if (hci->lm.responses_left) - bt_hci_mod_timer_1280ms(hci->lm.inquiry_done, hci->lm.inquiry_length); - else - bt_hci_inquiry_done(hci); - - if (hci->lm.periodic) - bt_hci_mod_timer_1280ms(hci->lm.inquiry_next, hci->lm.inquiry_period); -} - -static void bt_hci_inquiry_next(void *opaque) -{ - struct bt_hci_s *hci = (struct bt_hci_s *) opaque; - - hci->lm.responses_left += hci->lm.responses; - hci->lm.responses = 0; - bt_hci_inquiry_start(hci, hci->lm.inquiry_length); -} - -static inline int bt_hci_handle_bad(struct bt_hci_s *hci, uint16_t handle) -{ - return !(handle & HCI_HANDLE_OFFSET) || - handle >= (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX) || - !hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link; -} - -static inline int bt_hci_role_master(struct bt_hci_s *hci, uint16_t handle) -{ - return !!(hci->lm.role_bmp & (1 << (handle & ~HCI_HANDLE_OFFSET))); -} - -static inline struct bt_device_s *bt_hci_remote_dev(struct bt_hci_s *hci, - uint16_t handle) -{ - struct bt_link_s *link = hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link; - - return bt_hci_role_master(hci, handle) ? link->slave : link->host; -} - -static void bt_hci_mode_tick(void *opaque); -static void bt_hci_lmp_link_establish(struct bt_hci_s *hci, - struct bt_link_s *link, int master) -{ - hci->lm.handle[hci->lm.last_handle].link = link; - - if (master) { - /* We are the master side of an ACL link */ - hci->lm.role_bmp |= 1 << hci->lm.last_handle; - - hci->lm.handle[hci->lm.last_handle].lmp_acl_data = - link->slave->lmp_acl_data; - } else { - /* We are the slave side of an ACL link */ - hci->lm.role_bmp &= ~(1 << hci->lm.last_handle); - - hci->lm.handle[hci->lm.last_handle].lmp_acl_data = - link->host->lmp_acl_resp; - } - - /* Mode */ - if (master) { - link->acl_mode = acl_active; - hci->lm.handle[hci->lm.last_handle].acl_mode_timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_mode_tick, link); - } -} - -static void bt_hci_lmp_link_teardown(struct bt_hci_s *hci, uint16_t handle) -{ - handle &= ~HCI_HANDLE_OFFSET; - hci->lm.handle[handle].link = NULL; - - if (bt_hci_role_master(hci, handle)) { - timer_del(hci->lm.handle[handle].acl_mode_timer); - timer_free(hci->lm.handle[handle].acl_mode_timer); - } -} - -static int bt_hci_connect(struct bt_hci_s *hci, bdaddr_t *bdaddr) -{ - struct bt_device_s *slave; - struct bt_link_s link; - - for (slave = hci->device.net->slave; slave; slave = slave->next) - if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr)) - break; - if (!slave || slave == &hci->device) - return -ENODEV; - - bacpy(&hci->lm.awaiting_bdaddr[hci->lm.connecting ++], &slave->bd_addr); - - link.slave = slave; - link.host = &hci->device; - link.slave->lmp_connection_request(&link); /* Always last */ - - return 0; -} - -static void bt_hci_connection_reject(struct bt_hci_s *hci, - struct bt_device_s *host, uint8_t because) -{ - struct bt_link_s link = { - .slave = &hci->device, - .host = host, - /* Rest uninitialised */ - }; - - host->reject_reason = because; - host->lmp_connection_complete(&link); -} - -static void bt_hci_connection_reject_event(struct bt_hci_s *hci, - bdaddr_t *bdaddr) -{ - evt_conn_complete params; - - params.status = HCI_NO_CONNECTION; - params.handle = 0; - bacpy(¶ms.bdaddr, bdaddr); - params.link_type = ACL_LINK; - params.encr_mode = 0x00; /* Encryption not required */ - bt_hci_event(hci, EVT_CONN_COMPLETE, ¶ms, EVT_CONN_COMPLETE_SIZE); -} - -static void bt_hci_connection_accept(struct bt_hci_s *hci, - struct bt_device_s *host) -{ - struct bt_hci_link_s *link = g_malloc0(sizeof(struct bt_hci_link_s)); - evt_conn_complete params; - uint16_t handle; - uint8_t status = HCI_SUCCESS; - int tries = HCI_HANDLES_MAX; - - /* Make a connection handle */ - do { - while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries) - hci->lm.last_handle &= HCI_HANDLES_MAX - 1; - handle = hci->lm.last_handle | HCI_HANDLE_OFFSET; - } while ((handle == hci->asb_handle || handle == hci->psb_handle) && - tries); - - if (!tries) { - g_free(link); - bt_hci_connection_reject(hci, host, HCI_REJECTED_LIMITED_RESOURCES); - status = HCI_NO_CONNECTION; - goto complete; - } - - link->btlink.slave = &hci->device; - link->btlink.host = host; - link->handle = handle; - - /* Link established */ - bt_hci_lmp_link_establish(hci, &link->btlink, 0); - -complete: - params.status = status; - params.handle = HNDL(handle); - bacpy(¶ms.bdaddr, &host->bd_addr); - params.link_type = ACL_LINK; - params.encr_mode = 0x00; /* Encryption not required */ - bt_hci_event(hci, EVT_CONN_COMPLETE, ¶ms, EVT_CONN_COMPLETE_SIZE); - - /* Neets to be done at the very end because it can trigger a (nested) - * disconnected, in case the other and had cancelled the request - * locally. */ - if (status == HCI_SUCCESS) { - host->reject_reason = 0; - host->lmp_connection_complete(&link->btlink); - } -} - -static void bt_hci_lmp_connection_request(struct bt_link_s *link) -{ - struct bt_hci_s *hci = hci_from_device(link->slave); - evt_conn_request params; - - if (hci->conn_req_host) { - bt_hci_connection_reject(hci, link->host, - HCI_REJECTED_LIMITED_RESOURCES); - return; - } - hci->conn_req_host = link->host; - /* TODO: if masked and auto-accept, then auto-accept, - * if masked and not auto-accept, then auto-reject */ - /* TODO: kick the hci->conn_accept_timer, timeout after - * hci->conn_accept_tout * 0.625 msec */ - - bacpy(¶ms.bdaddr, &link->host->bd_addr); - memcpy(¶ms.dev_class, &link->host->class, sizeof(params.dev_class)); - params.link_type = ACL_LINK; - bt_hci_event(hci, EVT_CONN_REQUEST, ¶ms, EVT_CONN_REQUEST_SIZE); -} - -static void bt_hci_conn_accept_timeout(void *opaque) -{ - struct bt_hci_s *hci = (struct bt_hci_s *) opaque; - - if (!hci->conn_req_host) - /* Already accepted or rejected. If the other end cancelled the - * connection request then we still have to reject or accept it - * and then we'll get a disconnect. */ - return; - - /* TODO */ -} - -/* Remove from the list of devices which we wanted to connect to and - * are awaiting a response from. If the callback sees a response from - * a device which is not on the list it will assume it's a connection - * that's been cancelled by the host in the meantime and immediately - * try to detach the link and send a Connection Complete. */ -static int bt_hci_lmp_connection_ready(struct bt_hci_s *hci, - bdaddr_t *bdaddr) -{ - int i; - - for (i = 0; i < hci->lm.connecting; i ++) - if (!bacmp(&hci->lm.awaiting_bdaddr[i], bdaddr)) { - if (i < -- hci->lm.connecting) - bacpy(&hci->lm.awaiting_bdaddr[i], - &hci->lm.awaiting_bdaddr[hci->lm.connecting]); - return 0; - } - - return 1; -} - -static void bt_hci_lmp_connection_complete(struct bt_link_s *link) -{ - struct bt_hci_s *hci = hci_from_device(link->host); - evt_conn_complete params; - uint16_t handle; - uint8_t status = HCI_SUCCESS; - int tries = HCI_HANDLES_MAX; - - if (bt_hci_lmp_connection_ready(hci, &link->slave->bd_addr)) { - if (!hci->device.reject_reason) - link->slave->lmp_disconnect_slave(link); - handle = 0; - status = HCI_NO_CONNECTION; - goto complete; - } - - if (hci->device.reject_reason) { - handle = 0; - status = hci->device.reject_reason; - goto complete; - } - - /* Make a connection handle */ - do { - while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries) - hci->lm.last_handle &= HCI_HANDLES_MAX - 1; - handle = hci->lm.last_handle | HCI_HANDLE_OFFSET; - } while ((handle == hci->asb_handle || handle == hci->psb_handle) && - tries); - - if (!tries) { - link->slave->lmp_disconnect_slave(link); - status = HCI_NO_CONNECTION; - goto complete; - } - - /* Link established */ - link->handle = handle; - bt_hci_lmp_link_establish(hci, link, 1); - -complete: - params.status = status; - params.handle = HNDL(handle); - params.link_type = ACL_LINK; - bacpy(¶ms.bdaddr, &link->slave->bd_addr); - params.encr_mode = 0x00; /* Encryption not required */ - bt_hci_event(hci, EVT_CONN_COMPLETE, ¶ms, EVT_CONN_COMPLETE_SIZE); -} - -static void bt_hci_disconnect(struct bt_hci_s *hci, - uint16_t handle, int reason) -{ - struct bt_link_s *btlink = - hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link; - struct bt_hci_link_s *link; - evt_disconn_complete params; - - if (bt_hci_role_master(hci, handle)) { - btlink->slave->reject_reason = reason; - btlink->slave->lmp_disconnect_slave(btlink); - /* The link pointer is invalid from now on */ - - goto complete; - } - - btlink->host->reject_reason = reason; - btlink->host->lmp_disconnect_master(btlink); - - /* We are the slave, we get to clean this burden */ - link = (struct bt_hci_link_s *) btlink; - g_free(link); - -complete: - bt_hci_lmp_link_teardown(hci, handle); - - params.status = HCI_SUCCESS; - params.handle = HNDL(handle); - params.reason = HCI_CONNECTION_TERMINATED; - bt_hci_event(hci, EVT_DISCONN_COMPLETE, - ¶ms, EVT_DISCONN_COMPLETE_SIZE); -} - -/* TODO: use only one function */ -static void bt_hci_lmp_disconnect_host(struct bt_link_s *link) -{ - struct bt_hci_s *hci = hci_from_device(link->host); - uint16_t handle = link->handle; - evt_disconn_complete params; - - bt_hci_lmp_link_teardown(hci, handle); - - params.status = HCI_SUCCESS; - params.handle = HNDL(handle); - params.reason = hci->device.reject_reason; - bt_hci_event(hci, EVT_DISCONN_COMPLETE, - ¶ms, EVT_DISCONN_COMPLETE_SIZE); -} - -static void bt_hci_lmp_disconnect_slave(struct bt_link_s *btlink) -{ - struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; - struct bt_hci_s *hci = hci_from_device(btlink->slave); - uint16_t handle = link->handle; - evt_disconn_complete params; - - g_free(link); - - bt_hci_lmp_link_teardown(hci, handle); - - params.status = HCI_SUCCESS; - params.handle = HNDL(handle); - params.reason = hci->device.reject_reason; - bt_hci_event(hci, EVT_DISCONN_COMPLETE, - ¶ms, EVT_DISCONN_COMPLETE_SIZE); -} - -static int bt_hci_name_req(struct bt_hci_s *hci, bdaddr_t *bdaddr) -{ - struct bt_device_s *slave; - evt_remote_name_req_complete params; - - for (slave = hci->device.net->slave; slave; slave = slave->next) - if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr)) - break; - if (!slave) - return -ENODEV; - - bt_hci_event_status(hci, HCI_SUCCESS); - - params.status = HCI_SUCCESS; - bacpy(¶ms.bdaddr, &slave->bd_addr); - pstrcpy(params.name, sizeof(params.name), slave->lmp_name ?: ""); - bt_hci_event(hci, EVT_REMOTE_NAME_REQ_COMPLETE, - ¶ms, EVT_REMOTE_NAME_REQ_COMPLETE_SIZE); - - return 0; -} - -static int bt_hci_features_req(struct bt_hci_s *hci, uint16_t handle) -{ - struct bt_device_s *slave; - evt_read_remote_features_complete params; - - if (bt_hci_handle_bad(hci, handle)) - return -ENODEV; - - slave = bt_hci_remote_dev(hci, handle); - - bt_hci_event_status(hci, HCI_SUCCESS); - - params.status = HCI_SUCCESS; - params.handle = HNDL(handle); - params.features[0] = (slave->lmp_caps >> 0) & 0xff; - params.features[1] = (slave->lmp_caps >> 8) & 0xff; - params.features[2] = (slave->lmp_caps >> 16) & 0xff; - params.features[3] = (slave->lmp_caps >> 24) & 0xff; - params.features[4] = (slave->lmp_caps >> 32) & 0xff; - params.features[5] = (slave->lmp_caps >> 40) & 0xff; - params.features[6] = (slave->lmp_caps >> 48) & 0xff; - params.features[7] = (slave->lmp_caps >> 56) & 0xff; - bt_hci_event(hci, EVT_READ_REMOTE_FEATURES_COMPLETE, - ¶ms, EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE); - - return 0; -} - -static int bt_hci_version_req(struct bt_hci_s *hci, uint16_t handle) -{ - evt_read_remote_version_complete params; - - if (bt_hci_handle_bad(hci, handle)) - return -ENODEV; - - bt_hci_remote_dev(hci, handle); - - bt_hci_event_status(hci, HCI_SUCCESS); - - params.status = HCI_SUCCESS; - params.handle = HNDL(handle); - params.lmp_ver = 0x03; - params.manufacturer = cpu_to_le16(0xa000); - params.lmp_subver = cpu_to_le16(0xa607); - bt_hci_event(hci, EVT_READ_REMOTE_VERSION_COMPLETE, - ¶ms, EVT_READ_REMOTE_VERSION_COMPLETE_SIZE); - - return 0; -} - -static int bt_hci_clkoffset_req(struct bt_hci_s *hci, uint16_t handle) -{ - struct bt_device_s *slave; - evt_read_clock_offset_complete params; - - if (bt_hci_handle_bad(hci, handle)) - return -ENODEV; - - slave = bt_hci_remote_dev(hci, handle); - - bt_hci_event_status(hci, HCI_SUCCESS); - - params.status = HCI_SUCCESS; - params.handle = HNDL(handle); - /* TODO: return the clkoff *differenece* */ - params.clock_offset = slave->clkoff; /* Note: no swapping */ - bt_hci_event(hci, EVT_READ_CLOCK_OFFSET_COMPLETE, - ¶ms, EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE); - - return 0; -} - -static void bt_hci_event_mode(struct bt_hci_s *hci, struct bt_link_s *link, - uint16_t handle) -{ - evt_mode_change params = { - .status = HCI_SUCCESS, - .handle = HNDL(handle), - .mode = link->acl_mode, - .interval = cpu_to_le16(link->acl_interval), - }; - - bt_hci_event(hci, EVT_MODE_CHANGE, ¶ms, EVT_MODE_CHANGE_SIZE); -} - -static void bt_hci_lmp_mode_change_master(struct bt_hci_s *hci, - struct bt_link_s *link, int mode, uint16_t interval) -{ - link->acl_mode = mode; - link->acl_interval = interval; - - bt_hci_event_mode(hci, link, link->handle); - - link->slave->lmp_mode_change(link); -} - -static void bt_hci_lmp_mode_change_slave(struct bt_link_s *btlink) -{ - struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; - struct bt_hci_s *hci = hci_from_device(btlink->slave); - - bt_hci_event_mode(hci, btlink, link->handle); -} - -static int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle, - int interval, int mode) -{ - struct bt_hci_master_link_s *link; - - if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle)) - return -ENODEV; - - link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET]; - if (link->link->acl_mode != acl_active) { - bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED); - return 0; - } - - bt_hci_event_status(hci, HCI_SUCCESS); - - timer_mod(link->acl_mode_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - ((uint64_t)interval * 625) * 1000); - bt_hci_lmp_mode_change_master(hci, link->link, mode, interval); - - return 0; -} - -static int bt_hci_mode_cancel(struct bt_hci_s *hci, uint16_t handle, int mode) -{ - struct bt_hci_master_link_s *link; - - if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle)) - return -ENODEV; - - link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET]; - if (link->link->acl_mode != mode) { - bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED); - - return 0; - } - - bt_hci_event_status(hci, HCI_SUCCESS); - - timer_del(link->acl_mode_timer); - bt_hci_lmp_mode_change_master(hci, link->link, acl_active, 0); - - return 0; -} - -static void bt_hci_mode_tick(void *opaque) -{ - struct bt_link_s *link = opaque; - struct bt_hci_s *hci = hci_from_device(link->host); - - bt_hci_lmp_mode_change_master(hci, link, acl_active, 0); -} - -static void bt_hci_reset(struct bt_hci_s *hci) -{ - hci->acl_len = 0; - hci->last_cmd = 0; - hci->lm.connecting = 0; - - hci->event_mask[0] = 0xff; - hci->event_mask[1] = 0xff; - hci->event_mask[2] = 0xff; - hci->event_mask[3] = 0xff; - hci->event_mask[4] = 0xff; - hci->event_mask[5] = 0x1f; - hci->event_mask[6] = 0x00; - hci->event_mask[7] = 0x00; - hci->device.inquiry_scan = 0; - hci->device.page_scan = 0; - g_free((void *) hci->device.lmp_name); - hci->device.lmp_name = NULL; - hci->device.class[0] = 0x00; - hci->device.class[1] = 0x00; - hci->device.class[2] = 0x00; - hci->voice_setting = 0x0000; - hci->conn_accept_tout = 0x1f40; - hci->lm.inquiry_mode = 0x00; - - hci->psb_handle = 0x000; - hci->asb_handle = 0x000; - - /* XXX: timer_del(sl->acl_mode_timer); for all links */ - timer_del(hci->lm.inquiry_done); - timer_del(hci->lm.inquiry_next); - timer_del(hci->conn_accept_timer); -} - -static void bt_hci_read_local_version_rp(struct bt_hci_s *hci) -{ - read_local_version_rp lv = { - .status = HCI_SUCCESS, - .hci_ver = 0x03, - .hci_rev = cpu_to_le16(0xa607), - .lmp_ver = 0x03, - .manufacturer = cpu_to_le16(0xa000), - .lmp_subver = cpu_to_le16(0xa607), - }; - - bt_hci_event_complete(hci, &lv, READ_LOCAL_VERSION_RP_SIZE); -} - -static void bt_hci_read_local_commands_rp(struct bt_hci_s *hci) -{ - read_local_commands_rp lc = { - .status = HCI_SUCCESS, - .commands = { - /* Keep updated! */ - /* Also, keep in sync with hci->device.lmp_caps in bt_new_hci */ - 0xbf, 0x80, 0xf9, 0x03, 0xb2, 0xc0, 0x03, 0xc3, - 0x00, 0x0f, 0x80, 0x00, 0xc0, 0x00, 0xe8, 0x13, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - }; - - bt_hci_event_complete(hci, &lc, READ_LOCAL_COMMANDS_RP_SIZE); -} - -static void bt_hci_read_local_features_rp(struct bt_hci_s *hci) -{ - read_local_features_rp lf = { - .status = HCI_SUCCESS, - .features = { - (hci->device.lmp_caps >> 0) & 0xff, - (hci->device.lmp_caps >> 8) & 0xff, - (hci->device.lmp_caps >> 16) & 0xff, - (hci->device.lmp_caps >> 24) & 0xff, - (hci->device.lmp_caps >> 32) & 0xff, - (hci->device.lmp_caps >> 40) & 0xff, - (hci->device.lmp_caps >> 48) & 0xff, - (hci->device.lmp_caps >> 56) & 0xff, - }, - }; - - bt_hci_event_complete(hci, &lf, READ_LOCAL_FEATURES_RP_SIZE); -} - -static void bt_hci_read_local_ext_features_rp(struct bt_hci_s *hci, int page) -{ - read_local_ext_features_rp lef = { - .status = HCI_SUCCESS, - .page_num = page, - .max_page_num = 0x00, - .features = { - /* Keep updated! */ - 0x5f, 0x35, 0x85, 0x7e, 0x9b, 0x19, 0x00, 0x80, - }, - }; - if (page) - memset(lef.features, 0, sizeof(lef.features)); - - bt_hci_event_complete(hci, &lef, READ_LOCAL_EXT_FEATURES_RP_SIZE); -} - -static void bt_hci_read_buffer_size_rp(struct bt_hci_s *hci) -{ - read_buffer_size_rp bs = { - /* This can be made configurable, for one standard USB dongle HCI - * the four values are cpu_to_le16(0x0180), 0x40, - * cpu_to_le16(0x0008), cpu_to_le16(0x0008). */ - .status = HCI_SUCCESS, - .acl_mtu = cpu_to_le16(0x0200), - .sco_mtu = 0, - .acl_max_pkt = cpu_to_le16(0x0001), - .sco_max_pkt = cpu_to_le16(0x0000), - }; - - bt_hci_event_complete(hci, &bs, READ_BUFFER_SIZE_RP_SIZE); -} - -/* Deprecated in V2.0 (page 661) */ -static void bt_hci_read_country_code_rp(struct bt_hci_s *hci) -{ - read_country_code_rp cc ={ - .status = HCI_SUCCESS, - .country_code = 0x00, /* North America & Europe^1 and Japan */ - }; - - bt_hci_event_complete(hci, &cc, READ_COUNTRY_CODE_RP_SIZE); - - /* ^1. Except France, sorry */ -} - -static void bt_hci_read_bd_addr_rp(struct bt_hci_s *hci) -{ - read_bd_addr_rp ba = { - .status = HCI_SUCCESS, - .bdaddr = BAINIT(&hci->device.bd_addr), - }; - - bt_hci_event_complete(hci, &ba, READ_BD_ADDR_RP_SIZE); -} - -static int bt_hci_link_quality_rp(struct bt_hci_s *hci, uint16_t handle) -{ - read_link_quality_rp lq = { - .status = HCI_SUCCESS, - .handle = HNDL(handle), - .link_quality = 0xff, - }; - - if (bt_hci_handle_bad(hci, handle)) - lq.status = HCI_NO_CONNECTION; - - bt_hci_event_complete(hci, &lq, READ_LINK_QUALITY_RP_SIZE); - return 0; -} - -/* Generate a Command Complete event with only the Status parameter */ -static inline void bt_hci_event_complete_status(struct bt_hci_s *hci, - uint8_t status) -{ - bt_hci_event_complete(hci, &status, 1); -} - -static inline void bt_hci_event_complete_conn_cancel(struct bt_hci_s *hci, - uint8_t status, bdaddr_t *bd_addr) -{ - create_conn_cancel_rp params = { - .status = status, - .bdaddr = BAINIT(bd_addr), - }; - - bt_hci_event_complete(hci, ¶ms, CREATE_CONN_CANCEL_RP_SIZE); -} - -static inline void bt_hci_event_auth_complete(struct bt_hci_s *hci, - uint16_t handle) -{ - evt_auth_complete params = { - .status = HCI_SUCCESS, - .handle = HNDL(handle), - }; - - bt_hci_event(hci, EVT_AUTH_COMPLETE, ¶ms, EVT_AUTH_COMPLETE_SIZE); -} - -static inline void bt_hci_event_encrypt_change(struct bt_hci_s *hci, - uint16_t handle, uint8_t mode) -{ - evt_encrypt_change params = { - .status = HCI_SUCCESS, - .handle = HNDL(handle), - .encrypt = mode, - }; - - bt_hci_event(hci, EVT_ENCRYPT_CHANGE, ¶ms, EVT_ENCRYPT_CHANGE_SIZE); -} - -static inline void bt_hci_event_complete_name_cancel(struct bt_hci_s *hci, - bdaddr_t *bd_addr) -{ - remote_name_req_cancel_rp params = { - .status = HCI_INVALID_PARAMETERS, - .bdaddr = BAINIT(bd_addr), - }; - - bt_hci_event_complete(hci, ¶ms, REMOTE_NAME_REQ_CANCEL_RP_SIZE); -} - -static inline void bt_hci_event_read_remote_ext_features(struct bt_hci_s *hci, - uint16_t handle) -{ - evt_read_remote_ext_features_complete params = { - .status = HCI_UNSUPPORTED_FEATURE, - .handle = HNDL(handle), - /* Rest uninitialised */ - }; - - bt_hci_event(hci, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE, - ¶ms, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE); -} - -static inline void bt_hci_event_complete_lmp_handle(struct bt_hci_s *hci, - uint16_t handle) -{ - read_lmp_handle_rp params = { - .status = HCI_NO_CONNECTION, - .handle = HNDL(handle), - .reserved = 0, - /* Rest uninitialised */ - }; - - bt_hci_event_complete(hci, ¶ms, READ_LMP_HANDLE_RP_SIZE); -} - -static inline void bt_hci_event_complete_role_discovery(struct bt_hci_s *hci, - int status, uint16_t handle, int master) -{ - role_discovery_rp params = { - .status = status, - .handle = HNDL(handle), - .role = master ? 0x00 : 0x01, - }; - - bt_hci_event_complete(hci, ¶ms, ROLE_DISCOVERY_RP_SIZE); -} - -static inline void bt_hci_event_complete_flush(struct bt_hci_s *hci, - int status, uint16_t handle) -{ - flush_rp params = { - .status = status, - .handle = HNDL(handle), - }; - - bt_hci_event_complete(hci, ¶ms, FLUSH_RP_SIZE); -} - -static inline void bt_hci_event_complete_read_local_name(struct bt_hci_s *hci) -{ - read_local_name_rp params; - params.status = HCI_SUCCESS; - memset(params.name, 0, sizeof(params.name)); - if (hci->device.lmp_name) - pstrcpy(params.name, sizeof(params.name), hci->device.lmp_name); - - bt_hci_event_complete(hci, ¶ms, READ_LOCAL_NAME_RP_SIZE); -} - -static inline void bt_hci_event_complete_read_conn_accept_timeout( - struct bt_hci_s *hci) -{ - read_conn_accept_timeout_rp params = { - .status = HCI_SUCCESS, - .timeout = cpu_to_le16(hci->conn_accept_tout), - }; - - bt_hci_event_complete(hci, ¶ms, READ_CONN_ACCEPT_TIMEOUT_RP_SIZE); -} - -static inline void bt_hci_event_complete_read_scan_enable(struct bt_hci_s *hci) -{ - read_scan_enable_rp params = { - .status = HCI_SUCCESS, - .enable = - (hci->device.inquiry_scan ? SCAN_INQUIRY : 0) | - (hci->device.page_scan ? SCAN_PAGE : 0), - }; - - bt_hci_event_complete(hci, ¶ms, READ_SCAN_ENABLE_RP_SIZE); -} - -static inline void bt_hci_event_complete_read_local_class(struct bt_hci_s *hci) -{ - read_class_of_dev_rp params; - - params.status = HCI_SUCCESS; - memcpy(params.dev_class, hci->device.class, sizeof(params.dev_class)); - - bt_hci_event_complete(hci, ¶ms, READ_CLASS_OF_DEV_RP_SIZE); -} - -static inline void bt_hci_event_complete_voice_setting(struct bt_hci_s *hci) -{ - read_voice_setting_rp params = { - .status = HCI_SUCCESS, - .voice_setting = hci->voice_setting, /* Note: no swapping */ - }; - - bt_hci_event_complete(hci, ¶ms, READ_VOICE_SETTING_RP_SIZE); -} - -static inline void bt_hci_event_complete_read_inquiry_mode( - struct bt_hci_s *hci) -{ - read_inquiry_mode_rp params = { - .status = HCI_SUCCESS, - .mode = hci->lm.inquiry_mode, - }; - - bt_hci_event_complete(hci, ¶ms, READ_INQUIRY_MODE_RP_SIZE); -} - -static inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci, - uint16_t handle, int packets) -{ - uint16_t buf[EVT_NUM_COMP_PKTS_SIZE(1) / 2 + 1]; - evt_num_comp_pkts *params = (void *) ((uint8_t *) buf + 1); - - params->num_hndl = 1; - params->connection->handle = HNDL(handle); - params->connection->num_packets = cpu_to_le16(packets); - - bt_hci_event(hci, EVT_NUM_COMP_PKTS, params, EVT_NUM_COMP_PKTS_SIZE(1)); -} - -static void bt_submit_hci(struct HCIInfo *info, - const uint8_t *data, int length) -{ - struct bt_hci_s *hci = hci_from_info(info); - uint16_t cmd; - int paramlen, i; - - if (length < HCI_COMMAND_HDR_SIZE) - goto short_hci; - - memcpy(&hci->last_cmd, data, 2); - - cmd = (data[1] << 8) | data[0]; - paramlen = data[2]; - if (cmd_opcode_ogf(cmd) == 0 || cmd_opcode_ocf(cmd) == 0) /* NOP */ - return; - - data += HCI_COMMAND_HDR_SIZE; - length -= HCI_COMMAND_HDR_SIZE; - - if (paramlen > length) - return; - -#define PARAM(cmd, param) (((cmd##_cp *) data)->param) -#define PARAM16(cmd, param) lduw_le_p(&PARAM(cmd, param)) -#define PARAMHANDLE(cmd) PARAM16(cmd, handle) -#define LENGTH_CHECK(cmd) if (length < sizeof(cmd##_cp)) goto short_hci - /* Note: the supported commands bitmask in bt_hci_read_local_commands_rp - * needs to be updated every time a command is implemented here! */ - switch (cmd) { - case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY): - LENGTH_CHECK(inquiry); - - if (PARAM(inquiry, length) < 1) { - bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); - break; - } - - hci->lm.inquire = 1; - hci->lm.periodic = 0; - hci->lm.responses_left = PARAM(inquiry, num_rsp) ?: INT_MAX; - hci->lm.responses = 0; - bt_hci_event_status(hci, HCI_SUCCESS); - bt_hci_inquiry_start(hci, PARAM(inquiry, length)); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL): - if (!hci->lm.inquire || hci->lm.periodic) { - fprintf(stderr, "%s: Inquiry Cancel should only be issued after " - "the Inquiry command has been issued, a Command " - "Status event has been received for the Inquiry " - "command, and before the Inquiry Complete event " - "occurs", __func__); - bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED); - break; - } - - hci->lm.inquire = 0; - timer_del(hci->lm.inquiry_done); - bt_hci_event_complete_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY): - LENGTH_CHECK(periodic_inquiry); - - if (!(PARAM(periodic_inquiry, length) < - PARAM16(periodic_inquiry, min_period) && - PARAM16(periodic_inquiry, min_period) < - PARAM16(periodic_inquiry, max_period)) || - PARAM(periodic_inquiry, length) < 1 || - PARAM16(periodic_inquiry, min_period) < 2 || - PARAM16(periodic_inquiry, max_period) < 3) { - bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); - break; - } - - hci->lm.inquire = 1; - hci->lm.periodic = 1; - hci->lm.responses_left = PARAM(periodic_inquiry, num_rsp); - hci->lm.responses = 0; - hci->lm.inquiry_period = PARAM16(periodic_inquiry, max_period); - bt_hci_event_complete_status(hci, HCI_SUCCESS); - bt_hci_inquiry_start(hci, PARAM(periodic_inquiry, length)); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY): - if (!hci->lm.inquire || !hci->lm.periodic) { - fprintf(stderr, "%s: Inquiry Cancel should only be issued after " - "the Inquiry command has been issued, a Command " - "Status event has been received for the Inquiry " - "command, and before the Inquiry Complete event " - "occurs", __func__); - bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED); - break; - } - hci->lm.inquire = 0; - timer_del(hci->lm.inquiry_done); - timer_del(hci->lm.inquiry_next); - bt_hci_event_complete_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN): - LENGTH_CHECK(create_conn); - - if (hci->lm.connecting >= HCI_HANDLES_MAX) { - bt_hci_event_status(hci, HCI_REJECTED_LIMITED_RESOURCES); - break; - } - bt_hci_event_status(hci, HCI_SUCCESS); - - if (bt_hci_connect(hci, &PARAM(create_conn, bdaddr))) - bt_hci_connection_reject_event(hci, &PARAM(create_conn, bdaddr)); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_DISCONNECT): - LENGTH_CHECK(disconnect); - - if (bt_hci_handle_bad(hci, PARAMHANDLE(disconnect))) { - bt_hci_event_status(hci, HCI_NO_CONNECTION); - break; - } - - bt_hci_event_status(hci, HCI_SUCCESS); - bt_hci_disconnect(hci, PARAMHANDLE(disconnect), - PARAM(disconnect, reason)); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN_CANCEL): - LENGTH_CHECK(create_conn_cancel); - - if (bt_hci_lmp_connection_ready(hci, - &PARAM(create_conn_cancel, bdaddr))) { - for (i = 0; i < HCI_HANDLES_MAX; i ++) - if (bt_hci_role_master(hci, i) && hci->lm.handle[i].link && - !bacmp(&hci->lm.handle[i].link->slave->bd_addr, - &PARAM(create_conn_cancel, bdaddr))) - break; - - bt_hci_event_complete_conn_cancel(hci, i < HCI_HANDLES_MAX ? - HCI_ACL_CONNECTION_EXISTS : HCI_NO_CONNECTION, - &PARAM(create_conn_cancel, bdaddr)); - } else - bt_hci_event_complete_conn_cancel(hci, HCI_SUCCESS, - &PARAM(create_conn_cancel, bdaddr)); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ): - LENGTH_CHECK(accept_conn_req); - - if (!hci->conn_req_host || - bacmp(&PARAM(accept_conn_req, bdaddr), - &hci->conn_req_host->bd_addr)) { - bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); - break; - } - - bt_hci_event_status(hci, HCI_SUCCESS); - bt_hci_connection_accept(hci, hci->conn_req_host); - hci->conn_req_host = NULL; - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_REJECT_CONN_REQ): - LENGTH_CHECK(reject_conn_req); - - if (!hci->conn_req_host || - bacmp(&PARAM(reject_conn_req, bdaddr), - &hci->conn_req_host->bd_addr)) { - bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); - break; - } - - bt_hci_event_status(hci, HCI_SUCCESS); - bt_hci_connection_reject(hci, hci->conn_req_host, - PARAM(reject_conn_req, reason)); - bt_hci_connection_reject_event(hci, &hci->conn_req_host->bd_addr); - hci->conn_req_host = NULL; - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_AUTH_REQUESTED): - LENGTH_CHECK(auth_requested); - - if (bt_hci_handle_bad(hci, PARAMHANDLE(auth_requested))) - bt_hci_event_status(hci, HCI_NO_CONNECTION); - else { - bt_hci_event_status(hci, HCI_SUCCESS); - bt_hci_event_auth_complete(hci, PARAMHANDLE(auth_requested)); - } - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT): - LENGTH_CHECK(set_conn_encrypt); - - if (bt_hci_handle_bad(hci, PARAMHANDLE(set_conn_encrypt))) - bt_hci_event_status(hci, HCI_NO_CONNECTION); - else { - bt_hci_event_status(hci, HCI_SUCCESS); - bt_hci_event_encrypt_change(hci, - PARAMHANDLE(set_conn_encrypt), - PARAM(set_conn_encrypt, encrypt)); - } - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ): - LENGTH_CHECK(remote_name_req); - - if (bt_hci_name_req(hci, &PARAM(remote_name_req, bdaddr))) - bt_hci_event_status(hci, HCI_NO_CONNECTION); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL): - LENGTH_CHECK(remote_name_req_cancel); - - bt_hci_event_complete_name_cancel(hci, - &PARAM(remote_name_req_cancel, bdaddr)); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_FEATURES): - LENGTH_CHECK(read_remote_features); - - if (bt_hci_features_req(hci, PARAMHANDLE(read_remote_features))) - bt_hci_event_status(hci, HCI_NO_CONNECTION); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_EXT_FEATURES): - LENGTH_CHECK(read_remote_ext_features); - - if (bt_hci_handle_bad(hci, PARAMHANDLE(read_remote_ext_features))) - bt_hci_event_status(hci, HCI_NO_CONNECTION); - else { - bt_hci_event_status(hci, HCI_SUCCESS); - bt_hci_event_read_remote_ext_features(hci, - PARAMHANDLE(read_remote_ext_features)); - } - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_VERSION): - LENGTH_CHECK(read_remote_version); - - if (bt_hci_version_req(hci, PARAMHANDLE(read_remote_version))) - bt_hci_event_status(hci, HCI_NO_CONNECTION); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_CLOCK_OFFSET): - LENGTH_CHECK(read_clock_offset); - - if (bt_hci_clkoffset_req(hci, PARAMHANDLE(read_clock_offset))) - bt_hci_event_status(hci, HCI_NO_CONNECTION); - break; - - case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_LMP_HANDLE): - LENGTH_CHECK(read_lmp_handle); - - /* TODO: */ - bt_hci_event_complete_lmp_handle(hci, PARAMHANDLE(read_lmp_handle)); - break; - - case cmd_opcode_pack(OGF_LINK_POLICY, OCF_HOLD_MODE): - LENGTH_CHECK(hold_mode); - - if (PARAM16(hold_mode, min_interval) > - PARAM16(hold_mode, max_interval) || - PARAM16(hold_mode, min_interval) < 0x0002 || - PARAM16(hold_mode, max_interval) > 0xff00 || - (PARAM16(hold_mode, min_interval) & 1) || - (PARAM16(hold_mode, max_interval) & 1)) { - bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); - break; - } - - if (bt_hci_mode_change(hci, PARAMHANDLE(hold_mode), - PARAM16(hold_mode, max_interval), - acl_hold)) - bt_hci_event_status(hci, HCI_NO_CONNECTION); - break; - - case cmd_opcode_pack(OGF_LINK_POLICY, OCF_PARK_MODE): - LENGTH_CHECK(park_mode); - - if (PARAM16(park_mode, min_interval) > - PARAM16(park_mode, max_interval) || - PARAM16(park_mode, min_interval) < 0x000e || - (PARAM16(park_mode, min_interval) & 1) || - (PARAM16(park_mode, max_interval) & 1)) { - bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); - break; - } - - if (bt_hci_mode_change(hci, PARAMHANDLE(park_mode), - PARAM16(park_mode, max_interval), - acl_parked)) - bt_hci_event_status(hci, HCI_NO_CONNECTION); - break; - - case cmd_opcode_pack(OGF_LINK_POLICY, OCF_EXIT_PARK_MODE): - LENGTH_CHECK(exit_park_mode); - - if (bt_hci_mode_cancel(hci, PARAMHANDLE(exit_park_mode), - acl_parked)) - bt_hci_event_status(hci, HCI_NO_CONNECTION); - break; - - case cmd_opcode_pack(OGF_LINK_POLICY, OCF_ROLE_DISCOVERY): - LENGTH_CHECK(role_discovery); - - if (bt_hci_handle_bad(hci, PARAMHANDLE(role_discovery))) - bt_hci_event_complete_role_discovery(hci, - HCI_NO_CONNECTION, PARAMHANDLE(role_discovery), 0); - else - bt_hci_event_complete_role_discovery(hci, - HCI_SUCCESS, PARAMHANDLE(role_discovery), - bt_hci_role_master(hci, - PARAMHANDLE(role_discovery))); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_MASK): - LENGTH_CHECK(set_event_mask); - - memcpy(hci->event_mask, PARAM(set_event_mask, mask), 8); - bt_hci_event_complete_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_RESET): - bt_hci_reset(hci); - bt_hci_event_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_FLT): - if (length >= 1 && PARAM(set_event_flt, flt_type) == FLT_CLEAR_ALL) - /* No length check */; - else - LENGTH_CHECK(set_event_flt); - - /* Filters are not implemented */ - bt_hci_event_complete_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_FLUSH): - LENGTH_CHECK(flush); - - if (bt_hci_handle_bad(hci, PARAMHANDLE(flush))) - bt_hci_event_complete_flush(hci, - HCI_NO_CONNECTION, PARAMHANDLE(flush)); - else { - /* TODO: ordering? */ - bt_hci_event(hci, EVT_FLUSH_OCCURRED, - &PARAM(flush, handle), - EVT_FLUSH_OCCURRED_SIZE); - bt_hci_event_complete_flush(hci, - HCI_SUCCESS, PARAMHANDLE(flush)); - } - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME): - LENGTH_CHECK(change_local_name); - - g_free((void *) hci->device.lmp_name); - hci->device.lmp_name = g_strndup(PARAM(change_local_name, name), - sizeof(PARAM(change_local_name, name))); - bt_hci_event_complete_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME): - bt_hci_event_complete_read_local_name(hci); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CONN_ACCEPT_TIMEOUT): - bt_hci_event_complete_read_conn_accept_timeout(hci); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CONN_ACCEPT_TIMEOUT): - /* TODO */ - LENGTH_CHECK(write_conn_accept_timeout); - - if (PARAM16(write_conn_accept_timeout, timeout) < 0x0001 || - PARAM16(write_conn_accept_timeout, timeout) > 0xb540) { - bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); - break; - } - - hci->conn_accept_tout = PARAM16(write_conn_accept_timeout, timeout); - bt_hci_event_complete_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE): - bt_hci_event_complete_read_scan_enable(hci); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE): - LENGTH_CHECK(write_scan_enable); - - /* TODO: check that the remaining bits are all 0 */ - hci->device.inquiry_scan = - !!(PARAM(write_scan_enable, scan_enable) & SCAN_INQUIRY); - hci->device.page_scan = - !!(PARAM(write_scan_enable, scan_enable) & SCAN_PAGE); - bt_hci_event_complete_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CLASS_OF_DEV): - bt_hci_event_complete_read_local_class(hci); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV): - LENGTH_CHECK(write_class_of_dev); - - memcpy(hci->device.class, PARAM(write_class_of_dev, dev_class), - sizeof(PARAM(write_class_of_dev, dev_class))); - bt_hci_event_complete_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_VOICE_SETTING): - bt_hci_event_complete_voice_setting(hci); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING): - LENGTH_CHECK(write_voice_setting); - - hci->voice_setting = PARAM(write_voice_setting, voice_setting); - bt_hci_event_complete_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_HOST_NUMBER_OF_COMPLETED_PACKETS): - if (length < data[0] * 2 + 1) - goto short_hci; - - for (i = 0; i < data[0]; i ++) - if (bt_hci_handle_bad(hci, - data[i * 2 + 1] | (data[i * 2 + 2] << 8))) - bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQUIRY_MODE): - /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x40) - * else - * goto unknown_command */ - bt_hci_event_complete_read_inquiry_mode(hci); - break; - - case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE): - /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x80) - * else - * goto unknown_command */ - LENGTH_CHECK(write_inquiry_mode); - - if (PARAM(write_inquiry_mode, mode) > 0x01) { - bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); - break; - } - - hci->lm.inquiry_mode = PARAM(write_inquiry_mode, mode); - bt_hci_event_complete_status(hci, HCI_SUCCESS); - break; - - case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION): - bt_hci_read_local_version_rp(hci); - break; - - case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_COMMANDS): - bt_hci_read_local_commands_rp(hci); - break; - - case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES): - bt_hci_read_local_features_rp(hci); - break; - - case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES): - LENGTH_CHECK(read_local_ext_features); - - bt_hci_read_local_ext_features_rp(hci, - PARAM(read_local_ext_features, page_num)); - break; - - case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE): - bt_hci_read_buffer_size_rp(hci); - break; - - case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_COUNTRY_CODE): - bt_hci_read_country_code_rp(hci); - break; - - case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR): - bt_hci_read_bd_addr_rp(hci); - break; - - case cmd_opcode_pack(OGF_STATUS_PARAM, OCF_READ_LINK_QUALITY): - LENGTH_CHECK(read_link_quality); - - bt_hci_link_quality_rp(hci, PARAMHANDLE(read_link_quality)); - break; - - default: - bt_hci_event_status(hci, HCI_UNKNOWN_COMMAND); - break; - - short_hci: - error_report("%s: HCI packet too short (%iB)", __func__, length); - bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); - break; - } -} - -/* We could perform fragmentation here, we can't do "recombination" because - * at this layer the length of the payload is not know ahead, so we only - * know that a packet contained the last fragment of the SDU when the next - * SDU starts. */ -static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle, - const uint8_t *data, int start, int len) -{ - struct hci_acl_hdr *pkt = (void *) hci->acl_buf; - - /* TODO: packet flags */ - /* TODO: avoid memcpy'ing */ - - if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) { - error_report("%s: can't take ACL packets %i bytes long", - __func__, len); - return; - } - memcpy(hci->acl_buf + HCI_ACL_HDR_SIZE, data, len); - - pkt->handle = cpu_to_le16( - acl_handle_pack(handle, start ? ACL_START : ACL_CONT)); - pkt->dlen = cpu_to_le16(len); - hci->info.acl_recv(hci->info.opaque, - hci->acl_buf, len + HCI_ACL_HDR_SIZE); -} - -static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink, - const uint8_t *data, int start, int len) -{ - struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; - - bt_hci_lmp_acl_data(hci_from_device(btlink->slave), - link->handle, data, start, len); -} - -static void bt_hci_lmp_acl_data_host(struct bt_link_s *link, - const uint8_t *data, int start, int len) -{ - bt_hci_lmp_acl_data(hci_from_device(link->host), - link->handle, data, start, len); -} - -static void bt_submit_acl(struct HCIInfo *info, - const uint8_t *data, int length) -{ - struct bt_hci_s *hci = hci_from_info(info); - uint16_t handle; - int datalen, flags; - struct bt_link_s *link; - - if (length < HCI_ACL_HDR_SIZE) { - error_report("%s: ACL packet too short (%iB)", __func__, length); - return; - } - - handle = acl_handle((data[1] << 8) | data[0]); - flags = acl_flags((data[1] << 8) | data[0]); - datalen = (data[3] << 8) | data[2]; - data += HCI_ACL_HDR_SIZE; - length -= HCI_ACL_HDR_SIZE; - - if (bt_hci_handle_bad(hci, handle)) { - error_report("%s: invalid ACL handle %03x", __func__, handle); - /* TODO: signal an error */ - return; - } - handle &= ~HCI_HANDLE_OFFSET; - - if (datalen > length) { - error_report("%s: ACL packet too short (%iB < %iB)", - __func__, length, datalen); - return; - } - - link = hci->lm.handle[handle].link; - - if ((flags & ~3) == ACL_ACTIVE_BCAST) { - if (!hci->asb_handle) - hci->asb_handle = handle; - else if (handle != hci->asb_handle) { - error_report("%s: Bad handle %03x in Active Slave Broadcast", - __func__, handle); - /* TODO: signal an error */ - return; - } - - /* TODO */ - } - - if ((flags & ~3) == ACL_PICO_BCAST) { - if (!hci->psb_handle) - hci->psb_handle = handle; - else if (handle != hci->psb_handle) { - error_report("%s: Bad handle %03x in Parked Slave Broadcast", - __func__, handle); - /* TODO: signal an error */ - return; - } - - /* TODO */ - } - - /* TODO: increase counter and send EVT_NUM_COMP_PKTS */ - bt_hci_event_num_comp_pkts(hci, handle | HCI_HANDLE_OFFSET, 1); - - /* Do this last as it can trigger further events even in this HCI */ - hci->lm.handle[handle].lmp_acl_data(link, data, - (flags & 3) == ACL_START, length); -} - -static void bt_submit_sco(struct HCIInfo *info, - const uint8_t *data, int length) -{ - struct bt_hci_s *hci = hci_from_info(info); - uint16_t handle; - int datalen; - - if (length < 3) - return; - - handle = acl_handle((data[1] << 8) | data[0]); - datalen = data[2]; - length -= 3; - - if (bt_hci_handle_bad(hci, handle)) { - error_report("%s: invalid SCO handle %03x", __func__, handle); - return; - } - - if (datalen > length) { - error_report("%s: SCO packet too short (%iB < %iB)", - __func__, length, datalen); - return; - } - - /* TODO */ - - /* TODO: increase counter and send EVT_NUM_COMP_PKTS if synchronous - * Flow Control is enabled. - * (See Read/Write_Synchronous_Flow_Control_Enable on page 513 and - * page 514.) */ -} - -static uint8_t *bt_hci_evt_packet(void *opaque) -{ - /* TODO: allocate a packet from upper layer */ - struct bt_hci_s *s = opaque; - - return s->evt_buf; -} - -static void bt_hci_evt_submit(void *opaque, int len) -{ - /* TODO: notify upper layer */ - struct bt_hci_s *s = opaque; - - s->info.evt_recv(s->info.opaque, s->evt_buf, len); -} - -static int bt_hci_bdaddr_set(struct HCIInfo *info, const uint8_t *bd_addr) -{ - struct bt_hci_s *hci = hci_from_info(info); - - bacpy(&hci->device.bd_addr, (const bdaddr_t *) bd_addr); - return 0; -} - -static void bt_hci_done(struct HCIInfo *info); -static void bt_hci_destroy(struct bt_device_s *dev) -{ - struct bt_hci_s *hci = hci_from_device(dev); - - bt_hci_done(&hci->info); -} - -struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net) -{ - struct bt_hci_s *s = g_malloc0(sizeof(struct bt_hci_s)); - - s->lm.inquiry_done = timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_inquiry_done, s); - s->lm.inquiry_next = timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_inquiry_next, s); - s->conn_accept_timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, bt_hci_conn_accept_timeout, s); - - s->evt_packet = bt_hci_evt_packet; - s->evt_submit = bt_hci_evt_submit; - s->opaque = s; - - bt_device_init(&s->device, net); - s->device.lmp_connection_request = bt_hci_lmp_connection_request; - s->device.lmp_connection_complete = bt_hci_lmp_connection_complete; - s->device.lmp_disconnect_master = bt_hci_lmp_disconnect_host; - s->device.lmp_disconnect_slave = bt_hci_lmp_disconnect_slave; - s->device.lmp_acl_data = bt_hci_lmp_acl_data_slave; - s->device.lmp_acl_resp = bt_hci_lmp_acl_data_host; - s->device.lmp_mode_change = bt_hci_lmp_mode_change_slave; - - /* Keep updated! */ - /* Also keep in sync with supported commands bitmask in - * bt_hci_read_local_commands_rp */ - s->device.lmp_caps = 0x8000199b7e85355fll; - - bt_hci_reset(s); - - s->info.cmd_send = bt_submit_hci; - s->info.sco_send = bt_submit_sco; - s->info.acl_send = bt_submit_acl; - s->info.bdaddr_set = bt_hci_bdaddr_set; - - s->device.handle_destroy = bt_hci_destroy; - - error_setg(&s->replay_blocker, QERR_REPLAY_NOT_SUPPORTED, "-bt hci"); - replay_add_blocker(s->replay_blocker); - - return &s->info; -} - -struct HCIInfo *hci_init(const char *str) -{ - char *endp; - struct bt_scatternet_s *vlan = 0; - - if (!strcmp(str, "null")) - /* null */ - return &null_hci; - else if (!strncmp(str, "host", 4) && (str[4] == '\0' || str[4] == ':')) - /* host[:hciN] */ - return bt_host_hci(str[4] ? str + 5 : "hci0"); - else if (!strncmp(str, "hci", 3)) { - /* hci[,vlan=n] */ - if (str[3]) { - if (!strncmp(str + 3, ",vlan=", 6)) { - vlan = qemu_find_bt_vlan(strtol(str + 9, &endp, 0)); - if (*endp) - vlan = 0; - } - } else - vlan = qemu_find_bt_vlan(0); - if (vlan) - return bt_new_hci(vlan); - } - - error_report("Unknown bluetooth HCI `%s'.", str); - - return 0; -} - -static void bt_hci_done(struct HCIInfo *info) -{ - struct bt_hci_s *hci = hci_from_info(info); - int handle; - - bt_device_done(&hci->device); - - g_free((void *) hci->device.lmp_name); - - /* Be gentle and send DISCONNECT to all connected peers and those - * currently waiting for us to accept or reject a connection request. - * This frees the links. */ - if (hci->conn_req_host) { - bt_hci_connection_reject(hci, - hci->conn_req_host, HCI_OE_POWER_OFF); - return; - } - - for (handle = HCI_HANDLE_OFFSET; - handle < (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX); handle ++) - if (!bt_hci_handle_bad(hci, handle)) - bt_hci_disconnect(hci, handle, HCI_OE_POWER_OFF); - - /* TODO: this is not enough actually, there may be slaves from whom - * we have requested a connection who will soon (or not) respond with - * an accept or a reject, so we should also check if hci->lm.connecting - * is non-zero and if so, avoid freeing the hci but otherwise disappear - * from all qemu social life (e.g. stop scanning and request to be - * removed from s->device.net) and arrange for - * s->device.lmp_connection_complete to free the remaining bits once - * hci->lm.awaiting_bdaddr[] is empty. */ - - timer_free(hci->lm.inquiry_done); - timer_free(hci->lm.inquiry_next); - timer_free(hci->conn_accept_timer); - - g_free(hci); -} diff --git a/hw/bt/hid.c b/hw/bt/hid.c deleted file mode 100644 index 066ca99ed2..0000000000 --- a/hw/bt/hid.c +++ /dev/null @@ -1,553 +0,0 @@ -/* - * QEMU Bluetooth HID Profile wrapper for USB HID. - * - * Copyright (C) 2007-2008 OpenMoko, Inc. - * Written by Andrzej Zaborowski <andrew@openedhand.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu/timer.h" -#include "ui/console.h" -#include "hw/input/hid.h" -#include "hw/bt.h" - -enum hid_transaction_req { - BT_HANDSHAKE = 0x0, - BT_HID_CONTROL = 0x1, - BT_GET_REPORT = 0x4, - BT_SET_REPORT = 0x5, - BT_GET_PROTOCOL = 0x6, - BT_SET_PROTOCOL = 0x7, - BT_GET_IDLE = 0x8, - BT_SET_IDLE = 0x9, - BT_DATA = 0xa, - BT_DATC = 0xb, -}; - -enum hid_transaction_handshake { - BT_HS_SUCCESSFUL = 0x0, - BT_HS_NOT_READY = 0x1, - BT_HS_ERR_INVALID_REPORT_ID = 0x2, - BT_HS_ERR_UNSUPPORTED_REQUEST = 0x3, - BT_HS_ERR_INVALID_PARAMETER = 0x4, - BT_HS_ERR_UNKNOWN = 0xe, - BT_HS_ERR_FATAL = 0xf, -}; - -enum hid_transaction_control { - BT_HC_NOP = 0x0, - BT_HC_HARD_RESET = 0x1, - BT_HC_SOFT_RESET = 0x2, - BT_HC_SUSPEND = 0x3, - BT_HC_EXIT_SUSPEND = 0x4, - BT_HC_VIRTUAL_CABLE_UNPLUG = 0x5, -}; - -enum hid_protocol { - BT_HID_PROTO_BOOT = 0, - BT_HID_PROTO_REPORT = 1, -}; - -enum hid_boot_reportid { - BT_HID_BOOT_INVALID = 0, - BT_HID_BOOT_KEYBOARD, - BT_HID_BOOT_MOUSE, -}; - -enum hid_data_pkt { - BT_DATA_OTHER = 0, - BT_DATA_INPUT, - BT_DATA_OUTPUT, - BT_DATA_FEATURE, -}; - -#define BT_HID_MTU 48 - -/* HID interface requests */ -#define GET_REPORT 0xa101 -#define GET_IDLE 0xa102 -#define GET_PROTOCOL 0xa103 -#define SET_REPORT 0x2109 -#define SET_IDLE 0x210a -#define SET_PROTOCOL 0x210b - -struct bt_hid_device_s { - struct bt_l2cap_device_s btdev; - struct bt_l2cap_conn_params_s *control; - struct bt_l2cap_conn_params_s *interrupt; - HIDState hid; - - int proto; - int connected; - int data_type; - int intr_state; - struct { - int len; - uint8_t buffer[1024]; - } dataother, datain, dataout, feature, intrdataout; - enum { - bt_state_ready, - bt_state_transaction, - bt_state_suspend, - } state; -}; - -static void bt_hid_reset(struct bt_hid_device_s *s) -{ - struct bt_scatternet_s *net = s->btdev.device.net; - - /* Go as far as... */ - bt_l2cap_device_done(&s->btdev); - bt_l2cap_device_init(&s->btdev, net); - - hid_reset(&s->hid); - s->proto = BT_HID_PROTO_REPORT; - s->state = bt_state_ready; - s->dataother.len = 0; - s->datain.len = 0; - s->dataout.len = 0; - s->feature.len = 0; - s->intrdataout.len = 0; - s->intr_state = 0; -} - -static int bt_hid_out(struct bt_hid_device_s *s) -{ - if (s->data_type == BT_DATA_OUTPUT) { - /* nothing */ - ; - } - - if (s->data_type == BT_DATA_FEATURE) { - /* XXX: - * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE - * or a SET_REPORT? */ - ; - } - - return -1; -} - -static int bt_hid_in(struct bt_hid_device_s *s) -{ - s->datain.len = hid_keyboard_poll(&s->hid, s->datain.buffer, - sizeof(s->datain.buffer)); - return s->datain.len; -} - -static void bt_hid_send_handshake(struct bt_hid_device_s *s, int result) -{ - *s->control->sdu_out(s->control, 1) = - (BT_HANDSHAKE << 4) | result; - s->control->sdu_submit(s->control); -} - -static void bt_hid_send_control(struct bt_hid_device_s *s, int operation) -{ - *s->control->sdu_out(s->control, 1) = - (BT_HID_CONTROL << 4) | operation; - s->control->sdu_submit(s->control); -} - -static void bt_hid_disconnect(struct bt_hid_device_s *s) -{ - /* Disconnect s->control and s->interrupt */ -} - -static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type, - const uint8_t *data, int len) -{ - uint8_t *pkt, hdr = (BT_DATA << 4) | type; - int plen; - - do { - plen = MIN(len, ch->remote_mtu - 1); - pkt = ch->sdu_out(ch, plen + 1); - - pkt[0] = hdr; - if (plen) - memcpy(pkt + 1, data, plen); - ch->sdu_submit(ch); - - len -= plen; - data += plen; - hdr = (BT_DATC << 4) | type; - } while (plen == ch->remote_mtu - 1); -} - -static void bt_hid_control_transaction(struct bt_hid_device_s *s, - const uint8_t *data, int len) -{ - uint8_t type, parameter; - int rlen, ret = -1; - if (len < 1) - return; - - type = data[0] >> 4; - parameter = data[0] & 0xf; - - switch (type) { - case BT_HANDSHAKE: - case BT_DATA: - switch (parameter) { - default: - /* These are not expected to be sent this direction. */ - ret = BT_HS_ERR_INVALID_PARAMETER; - } - break; - - case BT_HID_CONTROL: - if (len != 1 || (parameter != BT_HC_VIRTUAL_CABLE_UNPLUG && - s->state == bt_state_transaction)) { - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - } - switch (parameter) { - case BT_HC_NOP: - break; - case BT_HC_HARD_RESET: - case BT_HC_SOFT_RESET: - bt_hid_reset(s); - break; - case BT_HC_SUSPEND: - if (s->state == bt_state_ready) - s->state = bt_state_suspend; - else - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - case BT_HC_EXIT_SUSPEND: - if (s->state == bt_state_suspend) - s->state = bt_state_ready; - else - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - case BT_HC_VIRTUAL_CABLE_UNPLUG: - bt_hid_disconnect(s); - break; - default: - ret = BT_HS_ERR_INVALID_PARAMETER; - } - break; - - case BT_GET_REPORT: - /* No ReportIDs declared. */ - if (((parameter & 8) && len != 3) || - (!(parameter & 8) && len != 1) || - s->state != bt_state_ready) { - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - } - if (parameter & 8) - rlen = data[2] | (data[3] << 8); - else - rlen = INT_MAX; - switch (parameter & 3) { - case BT_DATA_OTHER: - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - case BT_DATA_INPUT: - /* Here we can as well poll s->usbdev */ - bt_hid_send_data(s->control, BT_DATA_INPUT, - s->datain.buffer, MIN(rlen, s->datain.len)); - break; - case BT_DATA_OUTPUT: - bt_hid_send_data(s->control, BT_DATA_OUTPUT, - s->dataout.buffer, MIN(rlen, s->dataout.len)); - break; - case BT_DATA_FEATURE: - bt_hid_send_data(s->control, BT_DATA_FEATURE, - s->feature.buffer, MIN(rlen, s->feature.len)); - break; - } - break; - - case BT_SET_REPORT: - if (len < 2 || len > BT_HID_MTU || s->state != bt_state_ready || - (parameter & 3) == BT_DATA_OTHER || - (parameter & 3) == BT_DATA_INPUT) { - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - } - s->data_type = parameter & 3; - if (s->data_type == BT_DATA_OUTPUT) { - s->dataout.len = len - 1; - memcpy(s->dataout.buffer, data + 1, s->dataout.len); - } else { - s->feature.len = len - 1; - memcpy(s->feature.buffer, data + 1, s->feature.len); - } - if (len == BT_HID_MTU) - s->state = bt_state_transaction; - else - bt_hid_out(s); - break; - - case BT_GET_PROTOCOL: - if (len != 1 || s->state == bt_state_transaction) { - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - } - *s->control->sdu_out(s->control, 1) = s->proto; - s->control->sdu_submit(s->control); - break; - - case BT_SET_PROTOCOL: - if (len != 1 || s->state == bt_state_transaction || - (parameter != BT_HID_PROTO_BOOT && - parameter != BT_HID_PROTO_REPORT)) { - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - } - s->proto = parameter; - s->hid.protocol = parameter; - ret = BT_HS_SUCCESSFUL; - break; - - case BT_GET_IDLE: - if (len != 1 || s->state == bt_state_transaction) { - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - } - *s->control->sdu_out(s->control, 1) = s->hid.idle; - s->control->sdu_submit(s->control); - break; - - case BT_SET_IDLE: - if (len != 2 || s->state == bt_state_transaction) { - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - } - - s->hid.idle = data[1]; - /* XXX: Does this generate a handshake? */ - break; - - case BT_DATC: - if (len > BT_HID_MTU || s->state != bt_state_transaction) { - ret = BT_HS_ERR_INVALID_PARAMETER; - break; - } - if (s->data_type == BT_DATA_OUTPUT) { - memcpy(s->dataout.buffer + s->dataout.len, data + 1, len - 1); - s->dataout.len += len - 1; - } else { - memcpy(s->feature.buffer + s->feature.len, data + 1, len - 1); - s->feature.len += len - 1; - } - if (len < BT_HID_MTU) { - bt_hid_out(s); - s->state = bt_state_ready; - } - break; - - default: - ret = BT_HS_ERR_UNSUPPORTED_REQUEST; - } - - if (ret != -1) - bt_hid_send_handshake(s, ret); -} - -static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len) -{ - struct bt_hid_device_s *hid = opaque; - - bt_hid_control_transaction(hid, data, len); -} - -static void bt_hid_datain(HIDState *hs) -{ - struct bt_hid_device_s *hid = - container_of(hs, struct bt_hid_device_s, hid); - - /* If suspended, wake-up and send a wake-up event first. We might - * want to also inspect the input report and ignore event like - * mouse movements until a button event occurs. */ - if (hid->state == bt_state_suspend) { - hid->state = bt_state_ready; - } - - if (bt_hid_in(hid) > 0) - /* TODO: when in boot-mode precede any Input reports with the ReportID - * byte, here and in GetReport/SetReport on the Control channel. */ - bt_hid_send_data(hid->interrupt, BT_DATA_INPUT, - hid->datain.buffer, hid->datain.len); -} - -static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len) -{ - struct bt_hid_device_s *hid = opaque; - - if (len > BT_HID_MTU || len < 1) - goto bad; - if ((data[0] & 3) != BT_DATA_OUTPUT) - goto bad; - if ((data[0] >> 4) == BT_DATA) { - if (hid->intr_state) - goto bad; - - hid->data_type = BT_DATA_OUTPUT; - hid->intrdataout.len = 0; - } else if ((data[0] >> 4) == BT_DATC) { - if (!hid->intr_state) - goto bad; - } else - goto bad; - - memcpy(hid->intrdataout.buffer + hid->intrdataout.len, data + 1, len - 1); - hid->intrdataout.len += len - 1; - hid->intr_state = (len == BT_HID_MTU); - if (!hid->intr_state) { - memcpy(hid->dataout.buffer, hid->intrdataout.buffer, - hid->dataout.len = hid->intrdataout.len); - bt_hid_out(hid); - } - - return; -bad: - error_report("%s: bad transaction on Interrupt channel.", - __func__); -} - -/* "Virtual cable" plug/unplug event. */ -static void bt_hid_connected_update(struct bt_hid_device_s *hid) -{ - int prev = hid->connected; - - hid->connected = hid->control && hid->interrupt; - - /* Stop page-/inquiry-scanning when a host is connected. */ - hid->btdev.device.page_scan = !hid->connected; - hid->btdev.device.inquiry_scan = !hid->connected; - - if (hid->connected && !prev) { - hid_reset(&hid->hid); - hid->proto = BT_HID_PROTO_REPORT; - } - - /* Should set HIDVirtualCable in SDP (possibly need to check that SDP - * isn't destroyed yet, in case we're being called from handle_destroy) */ -} - -static void bt_hid_close_control(void *opaque) -{ - struct bt_hid_device_s *hid = opaque; - - hid->control = NULL; - bt_hid_connected_update(hid); -} - -static void bt_hid_close_interrupt(void *opaque) -{ - struct bt_hid_device_s *hid = opaque; - - hid->interrupt = NULL; - bt_hid_connected_update(hid); -} - -static int bt_hid_new_control_ch(struct bt_l2cap_device_s *dev, - struct bt_l2cap_conn_params_s *params) -{ - struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev; - - if (hid->control) - return 1; - - hid->control = params; - hid->control->opaque = hid; - hid->control->close = bt_hid_close_control; - hid->control->sdu_in = bt_hid_control_sdu; - - bt_hid_connected_update(hid); - - return 0; -} - -static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s *dev, - struct bt_l2cap_conn_params_s *params) -{ - struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev; - - if (hid->interrupt) - return 1; - - hid->interrupt = params; - hid->interrupt->opaque = hid; - hid->interrupt->close = bt_hid_close_interrupt; - hid->interrupt->sdu_in = bt_hid_interrupt_sdu; - - bt_hid_connected_update(hid); - - return 0; -} - -static void bt_hid_destroy(struct bt_device_s *dev) -{ - struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev; - - if (hid->connected) - bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG); - bt_l2cap_device_done(&hid->btdev); - - hid_free(&hid->hid); - - g_free(hid); -} - -enum peripheral_minor_class { - class_other = 0 << 4, - class_keyboard = 1 << 4, - class_pointing = 2 << 4, - class_combo = 3 << 4, -}; - -static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net, - enum peripheral_minor_class minor) -{ - struct bt_hid_device_s *s = g_malloc0(sizeof(*s)); - uint32_t class = - /* Format type */ - (0 << 0) | - /* Device class */ - (minor << 2) | - (5 << 8) | /* "Peripheral" */ - /* Service classes */ - (1 << 13) | /* Limited discoverable mode */ - (1 << 19); /* Capturing device (?) */ - - bt_l2cap_device_init(&s->btdev, net); - bt_l2cap_sdp_init(&s->btdev); - bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_CTRL, - BT_HID_MTU, bt_hid_new_control_ch); - bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR, - BT_HID_MTU, bt_hid_new_interrupt_ch); - - hid_init(&s->hid, HID_KEYBOARD, bt_hid_datain); - s->btdev.device.lmp_name = "BT Keyboard"; - - s->btdev.device.handle_destroy = bt_hid_destroy; - - s->btdev.device.class[0] = (class >> 0) & 0xff; - s->btdev.device.class[1] = (class >> 8) & 0xff; - s->btdev.device.class[2] = (class >> 16) & 0xff; - - return &s->btdev.device; -} - -struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net) -{ - return bt_hid_init(net, class_keyboard); -} diff --git a/hw/bt/l2cap.c b/hw/bt/l2cap.c deleted file mode 100644 index d67098a719..0000000000 --- a/hw/bt/l2cap.c +++ /dev/null @@ -1,1367 +0,0 @@ -/* - * QEMU Bluetooth L2CAP logic. - * - * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "qemu/timer.h" -#include "qemu/bswap.h" -#include "hw/bt.h" - -#define L2CAP_CID_MAX 0x100 /* Between 0x40 and 0x10000 */ - -struct l2cap_instance_s { - struct bt_link_s *link; - struct bt_l2cap_device_s *dev; - int role; - - uint8_t frame_in[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4))); - int frame_in_len; - - uint8_t frame_out[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4))); - int frame_out_len; - - /* Signalling channel timers. They exist per-request but we can make - * sure we have no more than one outstanding request at any time. */ - QEMUTimer *rtx; - QEMUTimer *ertx; - - int last_id; - int next_id; - - struct l2cap_chan_s { - struct bt_l2cap_conn_params_s params; - - void (*frame_in)(struct l2cap_chan_s *chan, uint16_t cid, - const l2cap_hdr *hdr, int len); - int mps; - int min_mtu; - - struct l2cap_instance_s *l2cap; - - /* Only allocated channels */ - uint16_t remote_cid; -#define L2CAP_CFG_INIT 2 -#define L2CAP_CFG_ACC 1 - int config_req_id; /* TODO: handle outgoing requests generically */ - int config; - - /* Only connection-oriented channels. Note: if we allow the tx and - * rx traffic to be in different modes at any time, we need two. */ - int mode; - - /* Only flow-controlled, connection-oriented channels */ - uint8_t sdu[65536]; /* TODO: dynamically allocate */ - int len_cur, len_total; - int rexmit; - int monitor_timeout; - QEMUTimer *monitor_timer; - QEMUTimer *retransmission_timer; - } *cid[L2CAP_CID_MAX]; - /* The channel state machine states map as following: - * CLOSED -> !cid[N] - * WAIT_CONNECT -> never occurs - * WAIT_CONNECT_RSP -> never occurs - * CONFIG -> cid[N] && config < 3 - * WAIT_CONFIG -> never occurs, cid[N] && config == 0 && !config_r - * WAIT_SEND_CONFIG -> never occurs, cid[N] && config == 1 && !config_r - * WAIT_CONFIG_REQ_RSP -> cid[N] && config == 0 && config_req_id - * WAIT_CONFIG_RSP -> cid[N] && config == 1 && config_req_id - * WAIT_CONFIG_REQ -> cid[N] && config == 2 - * OPEN -> cid[N] && config == 3 - * WAIT_DISCONNECT -> never occurs - */ - - struct l2cap_chan_s signalling_ch; - struct l2cap_chan_s group_ch; -}; - -struct slave_l2cap_instance_s { - struct bt_link_s link; /* Underlying logical link (ACL) */ - struct l2cap_instance_s l2cap; -}; - -struct bt_l2cap_psm_s { - int psm; - int min_mtu; - int (*new_channel)(struct bt_l2cap_device_s *device, - struct bt_l2cap_conn_params_s *params); - struct bt_l2cap_psm_s *next; -}; - -static const uint16_t l2cap_fcs16_table[256] = { - 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, - 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, - 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, - 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, - 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, - 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, - 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, - 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, - 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, - 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, - 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, - 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, - 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, - 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, - 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, - 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, - 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, - 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, - 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, - 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, - 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, - 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, - 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, - 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, - 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, - 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, - 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, - 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, - 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, - 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, - 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, - 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, -}; - -static uint16_t l2cap_fcs16(const uint8_t *message, int len) -{ - uint16_t fcs = 0x0000; - - while (len --) -#if 0 - { - int i; - - fcs ^= *message ++; - for (i = 8; i; -- i) - if (fcs & 1) - fcs = (fcs >> 1) ^ 0xa001; - else - fcs = (fcs >> 1); - } -#else - fcs = (fcs >> 8) ^ l2cap_fcs16_table[(fcs ^ *message ++) & 0xff]; -#endif - - return fcs; -} - -/* L2CAP layer logic (protocol) */ - -static void l2cap_retransmission_timer_update(struct l2cap_chan_s *ch) -{ -#if 0 - if (ch->mode != L2CAP_MODE_BASIC && ch->rexmit) - timer_mod(ch->retransmission_timer); - else - timer_del(ch->retransmission_timer); -#endif -} - -static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch) -{ -#if 0 - if (ch->mode != L2CAP_MODE_BASIC && !ch->rexmit) - timer_mod(ch->monitor_timer); - else - timer_del(ch->monitor_timer); -#endif -} - -static void l2cap_command_reject(struct l2cap_instance_s *l2cap, int id, - uint16_t reason, const void *data, int plen) -{ - uint8_t *pkt; - l2cap_cmd_hdr *hdr; - l2cap_cmd_rej *params; - uint16_t len; - - reason = cpu_to_le16(reason); - len = cpu_to_le16(L2CAP_CMD_REJ_SIZE + plen); - - pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, - L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE + plen); - hdr = (void *) (pkt + 0); - params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); - - hdr->code = L2CAP_COMMAND_REJ; - hdr->ident = id; - memcpy(&hdr->len, &len, sizeof(hdr->len)); - memcpy(¶ms->reason, &reason, sizeof(reason)); - if (plen) - memcpy(pkt + L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE, data, plen); - - l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); -} - -static void l2cap_command_reject_cid(struct l2cap_instance_s *l2cap, int id, - uint16_t reason, uint16_t dcid, uint16_t scid) -{ - l2cap_cmd_rej_cid params = { - .dcid = dcid, - .scid = scid, - }; - - l2cap_command_reject(l2cap, id, reason, ¶ms, L2CAP_CMD_REJ_CID_SIZE); -} - -static void l2cap_connection_response(struct l2cap_instance_s *l2cap, - int dcid, int scid, int result, int status) -{ - uint8_t *pkt; - l2cap_cmd_hdr *hdr; - l2cap_conn_rsp *params; - - pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, - L2CAP_CMD_HDR_SIZE + L2CAP_CONN_RSP_SIZE); - hdr = (void *) (pkt + 0); - params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); - - hdr->code = L2CAP_CONN_RSP; - hdr->ident = l2cap->last_id; - hdr->len = cpu_to_le16(L2CAP_CONN_RSP_SIZE); - - params->dcid = cpu_to_le16(dcid); - params->scid = cpu_to_le16(scid); - params->result = cpu_to_le16(result); - params->status = cpu_to_le16(status); - - l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); -} - -static void l2cap_configuration_request(struct l2cap_instance_s *l2cap, - int dcid, int flag, const uint8_t *data, int len) -{ - uint8_t *pkt; - l2cap_cmd_hdr *hdr; - l2cap_conf_req *params; - - pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, - L2CAP_CMD_HDR_SIZE + L2CAP_CONF_REQ_SIZE(len)); - hdr = (void *) (pkt + 0); - params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); - - /* TODO: unify the id sequencing */ - l2cap->last_id = l2cap->next_id; - l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1; - - hdr->code = L2CAP_CONF_REQ; - hdr->ident = l2cap->last_id; - hdr->len = cpu_to_le16(L2CAP_CONF_REQ_SIZE(len)); - - params->dcid = cpu_to_le16(dcid); - params->flags = cpu_to_le16(flag); - if (len) - memcpy(params->data, data, len); - - l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); -} - -static void l2cap_configuration_response(struct l2cap_instance_s *l2cap, - int scid, int flag, int result, const uint8_t *data, int len) -{ - uint8_t *pkt; - l2cap_cmd_hdr *hdr; - l2cap_conf_rsp *params; - - pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, - L2CAP_CMD_HDR_SIZE + L2CAP_CONF_RSP_SIZE(len)); - hdr = (void *) (pkt + 0); - params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); - - hdr->code = L2CAP_CONF_RSP; - hdr->ident = l2cap->last_id; - hdr->len = cpu_to_le16(L2CAP_CONF_RSP_SIZE(len)); - - params->scid = cpu_to_le16(scid); - params->flags = cpu_to_le16(flag); - params->result = cpu_to_le16(result); - if (len) - memcpy(params->data, data, len); - - l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); -} - -static void l2cap_disconnection_response(struct l2cap_instance_s *l2cap, - int dcid, int scid) -{ - uint8_t *pkt; - l2cap_cmd_hdr *hdr; - l2cap_disconn_rsp *params; - - pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, - L2CAP_CMD_HDR_SIZE + L2CAP_DISCONN_RSP_SIZE); - hdr = (void *) (pkt + 0); - params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); - - hdr->code = L2CAP_DISCONN_RSP; - hdr->ident = l2cap->last_id; - hdr->len = cpu_to_le16(L2CAP_DISCONN_RSP_SIZE); - - params->dcid = cpu_to_le16(dcid); - params->scid = cpu_to_le16(scid); - - l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); -} - -static void l2cap_echo_response(struct l2cap_instance_s *l2cap, - const uint8_t *data, int len) -{ - uint8_t *pkt; - l2cap_cmd_hdr *hdr; - uint8_t *params; - - pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, - L2CAP_CMD_HDR_SIZE + len); - hdr = (void *) (pkt + 0); - params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); - - hdr->code = L2CAP_ECHO_RSP; - hdr->ident = l2cap->last_id; - hdr->len = cpu_to_le16(len); - - memcpy(params, data, len); - - l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); -} - -static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type, - int result, const uint8_t *data, int len) -{ - uint8_t *pkt; - l2cap_cmd_hdr *hdr; - l2cap_info_rsp *params; - - pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params, - L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + len); - hdr = (void *) (pkt + 0); - params = (void *) (pkt + L2CAP_CMD_HDR_SIZE); - - hdr->code = L2CAP_INFO_RSP; - hdr->ident = l2cap->last_id; - hdr->len = cpu_to_le16(L2CAP_INFO_RSP_SIZE + len); - - params->type = cpu_to_le16(type); - params->result = cpu_to_le16(result); - if (len) - memcpy(params->data, data, len); - - l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params); -} - -static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len); -static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms); -#if 0 -static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len); -static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm); -#endif -static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, - const l2cap_hdr *hdr, int len); -static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, - const l2cap_hdr *hdr, int len); - -static int l2cap_cid_new(struct l2cap_instance_s *l2cap) -{ - int i; - - for (i = L2CAP_CID_ALLOC; i < L2CAP_CID_MAX; i ++) - if (!l2cap->cid[i]) - return i; - - return L2CAP_CID_INVALID; -} - -static inline struct bt_l2cap_psm_s *l2cap_psm( - struct bt_l2cap_device_s *device, int psm) -{ - struct bt_l2cap_psm_s *ret = device->first_psm; - - while (ret && ret->psm != psm) - ret = ret->next; - - return ret; -} - -static struct l2cap_chan_s *l2cap_channel_open(struct l2cap_instance_s *l2cap, - int psm, int source_cid) -{ - struct l2cap_chan_s *ch = NULL; - struct bt_l2cap_psm_s *psm_info; - int result, status; - int cid = l2cap_cid_new(l2cap); - - if (cid) { - /* See what the channel is to be used for.. */ - psm_info = l2cap_psm(l2cap->dev, psm); - - if (psm_info) { - /* Device supports this use-case. */ - ch = g_malloc0(sizeof(*ch)); - ch->params.sdu_out = l2cap_bframe_out; - ch->params.sdu_submit = l2cap_bframe_submit; - ch->frame_in = l2cap_bframe_in; - ch->mps = 65536; - ch->min_mtu = MAX(48, psm_info->min_mtu); - ch->params.remote_mtu = MAX(672, ch->min_mtu); - ch->remote_cid = source_cid; - ch->mode = L2CAP_MODE_BASIC; - ch->l2cap = l2cap; - - /* Does it feel like opening yet another channel though? */ - if (!psm_info->new_channel(l2cap->dev, &ch->params)) { - l2cap->cid[cid] = ch; - - result = L2CAP_CR_SUCCESS; - status = L2CAP_CS_NO_INFO; - } else { - g_free(ch); - ch = NULL; - result = L2CAP_CR_NO_MEM; - status = L2CAP_CS_NO_INFO; - } - } else { - result = L2CAP_CR_BAD_PSM; - status = L2CAP_CS_NO_INFO; - } - } else { - result = L2CAP_CR_NO_MEM; - status = L2CAP_CS_NO_INFO; - } - - l2cap_connection_response(l2cap, cid, source_cid, result, status); - - return ch; -} - -static void l2cap_channel_close(struct l2cap_instance_s *l2cap, - int cid, int source_cid) -{ - struct l2cap_chan_s *ch = NULL; - - /* According to Volume 3, section 6.1.1, pg 1048 of BT Core V2.0, a - * connection in CLOSED state still responds with a L2CAP_DisconnectRsp - * message on an L2CAP_DisconnectReq event. */ - if (unlikely(cid < L2CAP_CID_ALLOC)) { - l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL, - cid, source_cid); - return; - } - if (likely(cid >= L2CAP_CID_ALLOC && cid < L2CAP_CID_MAX)) - ch = l2cap->cid[cid]; - - if (likely(ch)) { - if (ch->remote_cid != source_cid) { - error_report("%s: Ignoring a Disconnection Request with the " - "invalid SCID %04x.", __func__, source_cid); - return; - } - - l2cap->cid[cid] = NULL; - - ch->params.close(ch->params.opaque); - g_free(ch); - } - - l2cap_disconnection_response(l2cap, cid, source_cid); -} - -static void l2cap_channel_config_null(struct l2cap_instance_s *l2cap, - struct l2cap_chan_s *ch) -{ - l2cap_configuration_request(l2cap, ch->remote_cid, 0, NULL, 0); - ch->config_req_id = l2cap->last_id; - ch->config &= ~L2CAP_CFG_INIT; -} - -static void l2cap_channel_config_req_event(struct l2cap_instance_s *l2cap, - struct l2cap_chan_s *ch) -{ - /* Use all default channel options and terminate negotiation. */ - l2cap_channel_config_null(l2cap, ch); -} - -static int l2cap_channel_config(struct l2cap_instance_s *l2cap, - struct l2cap_chan_s *ch, int flag, - const uint8_t *data, int len) -{ - l2cap_conf_opt *opt; - l2cap_conf_opt_qos *qos; - uint32_t val; - uint8_t rsp[len]; - int result = L2CAP_CONF_SUCCESS; - - data = memcpy(rsp, data, len); - while (len) { - opt = (void *) data; - - if (len < L2CAP_CONF_OPT_SIZE || - len < L2CAP_CONF_OPT_SIZE + opt->len) { - result = L2CAP_CONF_REJECT; - break; - } - data += L2CAP_CONF_OPT_SIZE + opt->len; - len -= L2CAP_CONF_OPT_SIZE + opt->len; - - switch (opt->type & 0x7f) { - case L2CAP_CONF_MTU: - if (opt->len != 2) { - result = L2CAP_CONF_REJECT; - break; - } - - /* MTU */ - val = lduw_le_p(opt->val); - if (val < ch->min_mtu) { - stw_le_p(opt->val, ch->min_mtu); - result = L2CAP_CONF_UNACCEPT; - break; - } - - ch->params.remote_mtu = val; - break; - - case L2CAP_CONF_FLUSH_TO: - if (opt->len != 2) { - result = L2CAP_CONF_REJECT; - break; - } - - /* Flush Timeout */ - val = lduw_le_p(opt->val); - if (val < 0x0001) { - opt->val[0] = 0xff; - opt->val[1] = 0xff; - result = L2CAP_CONF_UNACCEPT; - break; - } - break; - - case L2CAP_CONF_QOS: - if (opt->len != L2CAP_CONF_OPT_QOS_SIZE) { - result = L2CAP_CONF_REJECT; - break; - } - qos = (void *) opt->val; - - /* Flags */ - val = qos->flags; - if (val) { - qos->flags = 0; - result = L2CAP_CONF_UNACCEPT; - } - - /* Service type */ - val = qos->service_type; - if (val != L2CAP_CONF_QOS_BEST_EFFORT && - val != L2CAP_CONF_QOS_NO_TRAFFIC) { - qos->service_type = L2CAP_CONF_QOS_BEST_EFFORT; - result = L2CAP_CONF_UNACCEPT; - } - - if (val != L2CAP_CONF_QOS_NO_TRAFFIC) { - /* XXX: These values should possibly be calculated - * based on LM / baseband properties also. */ - - /* Token rate */ - val = le32_to_cpu(qos->token_rate); - if (val == L2CAP_CONF_QOS_WILDCARD) - qos->token_rate = cpu_to_le32(0x100000); - - /* Token bucket size */ - val = le32_to_cpu(qos->token_bucket_size); - if (val == L2CAP_CONF_QOS_WILDCARD) - qos->token_bucket_size = cpu_to_le32(65500); - - /* Any Peak bandwidth value is correct to return as-is */ - /* Any Access latency value is correct to return as-is */ - /* Any Delay variation value is correct to return as-is */ - } - break; - - case L2CAP_CONF_RFC: - if (opt->len != 9) { - result = L2CAP_CONF_REJECT; - break; - } - - /* Mode */ - val = opt->val[0]; - switch (val) { - case L2CAP_MODE_BASIC: - ch->mode = val; - ch->frame_in = l2cap_bframe_in; - - /* All other parameters shall be ignored */ - break; - - case L2CAP_MODE_RETRANS: - case L2CAP_MODE_FLOWCTL: - ch->mode = val; - ch->frame_in = l2cap_iframe_in; - /* Note: most of these parameters refer to incoming traffic - * so we don't need to save them as long as we can accept - * incoming PDUs at any values of the parameters. */ - - /* TxWindow size */ - val = opt->val[1]; - if (val < 1 || val > 32) { - opt->val[1] = 32; - result = L2CAP_CONF_UNACCEPT; - break; - } - - /* MaxTransmit */ - val = opt->val[2]; - if (val < 1) { - opt->val[2] = 1; - result = L2CAP_CONF_UNACCEPT; - break; - } - - /* Remote Retransmission time-out shouldn't affect local - * operation (?) */ - - /* The Monitor time-out drives the local Monitor timer (?), - * so save the value. */ - val = (opt->val[6] << 8) | opt->val[5]; - if (val < 30) { - opt->val[5] = 100 & 0xff; - opt->val[6] = 100 >> 8; - result = L2CAP_CONF_UNACCEPT; - break; - } - ch->monitor_timeout = val; - l2cap_monitor_timer_update(ch); - - /* MPS */ - val = (opt->val[8] << 8) | opt->val[7]; - if (val < ch->min_mtu) { - opt->val[7] = ch->min_mtu & 0xff; - opt->val[8] = ch->min_mtu >> 8; - result = L2CAP_CONF_UNACCEPT; - break; - } - ch->mps = val; - break; - - default: - result = L2CAP_CONF_UNACCEPT; - break; - } - break; - - default: - if (!(opt->type >> 7)) - result = L2CAP_CONF_UNKNOWN; - break; - } - - if (result != L2CAP_CONF_SUCCESS) - break; /* XXX: should continue? */ - } - - l2cap_configuration_response(l2cap, ch->remote_cid, - flag, result, rsp, len); - - return result == L2CAP_CONF_SUCCESS && !flag; -} - -static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap, - int flag, int cid, const uint8_t *data, int len) -{ - struct l2cap_chan_s *ch; - - if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) { - l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL, - cid, 0x0000); - return; - } - ch = l2cap->cid[cid]; - - /* From OPEN go to WAIT_CONFIG_REQ and from WAIT_CONFIG_REQ_RSP to - * WAIT_CONFIG_REQ_RSP. This is assuming the transition chart for OPEN - * on pg 1053, section 6.1.5, volume 3 of BT Core V2.0 has a mistake - * and on options-acceptable we go back to OPEN and otherwise to - * WAIT_CONFIG_REQ and not the other way. */ - ch->config &= ~L2CAP_CFG_ACC; - - if (l2cap_channel_config(l2cap, ch, flag, data, len)) - /* Go to OPEN or WAIT_CONFIG_RSP */ - ch->config |= L2CAP_CFG_ACC; - - /* TODO: if the incoming traffic flow control or retransmission mode - * changed then we probably need to also generate the - * ConfigureChannel_Req event and set the outgoing traffic to the same - * mode. */ - if (!(ch->config & L2CAP_CFG_INIT) && (ch->config & L2CAP_CFG_ACC) && - !ch->config_req_id) - l2cap_channel_config_req_event(l2cap, ch); -} - -static int l2cap_channel_config_rsp_msg(struct l2cap_instance_s *l2cap, - int result, int flag, int cid, const uint8_t *data, int len) -{ - struct l2cap_chan_s *ch; - - if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) { - l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL, - cid, 0x0000); - return 0; - } - ch = l2cap->cid[cid]; - - if (ch->config_req_id != l2cap->last_id) - return 1; - ch->config_req_id = 0; - - if (result == L2CAP_CONF_SUCCESS) { - if (!flag) - ch->config |= L2CAP_CFG_INIT; - else - l2cap_channel_config_null(l2cap, ch); - } else - /* Retry until we succeed */ - l2cap_channel_config_req_event(l2cap, ch); - - return 0; -} - -static void l2cap_channel_open_req_msg(struct l2cap_instance_s *l2cap, - int psm, int source_cid) -{ - struct l2cap_chan_s *ch = l2cap_channel_open(l2cap, psm, source_cid); - - if (!ch) - return; - - /* Optional */ - if (!(ch->config & L2CAP_CFG_INIT) && !ch->config_req_id) - l2cap_channel_config_req_event(l2cap, ch); -} - -static void l2cap_info(struct l2cap_instance_s *l2cap, int type) -{ - uint8_t data[4]; - int len = 0; - int result = L2CAP_IR_SUCCESS; - - switch (type) { - case L2CAP_IT_CL_MTU: - data[len ++] = l2cap->group_ch.mps & 0xff; - data[len ++] = l2cap->group_ch.mps >> 8; - break; - - case L2CAP_IT_FEAT_MASK: - /* (Prematurely) report Flow control and Retransmission modes. */ - data[len ++] = 0x03; - data[len ++] = 0x00; - data[len ++] = 0x00; - data[len ++] = 0x00; - break; - - default: - result = L2CAP_IR_NOTSUPP; - } - - l2cap_info_response(l2cap, type, result, data, len); -} - -static void l2cap_command(struct l2cap_instance_s *l2cap, int code, int id, - const uint8_t *params, int len) -{ - int err; - -#if 0 - /* TODO: do the IDs really have to be in sequence? */ - if (!id || (id != l2cap->last_id && id != l2cap->next_id)) { - error_report("%s: out of sequence command packet ignored.", - __func__); - return; - } -#else - l2cap->next_id = id; -#endif - if (id == l2cap->next_id) { - l2cap->last_id = l2cap->next_id; - l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1; - } else { - /* TODO: Need to re-send the same response, without re-executing - * the corresponding command! */ - } - - switch (code) { - case L2CAP_COMMAND_REJ: - if (unlikely(len != 2 && len != 4 && len != 6)) { - err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; - goto reject; - } - - /* We never issue commands other than Command Reject currently. */ - error_report("%s: stray Command Reject (%02x, %04x) " - "packet, ignoring.", __func__, id, - le16_to_cpu(((l2cap_cmd_rej *) params)->reason)); - break; - - case L2CAP_CONN_REQ: - if (unlikely(len != L2CAP_CONN_REQ_SIZE)) { - err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; - goto reject; - } - - l2cap_channel_open_req_msg(l2cap, - le16_to_cpu(((l2cap_conn_req *) params)->psm), - le16_to_cpu(((l2cap_conn_req *) params)->scid)); - break; - - case L2CAP_CONN_RSP: - if (unlikely(len != L2CAP_CONN_RSP_SIZE)) { - err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; - goto reject; - } - - /* We never issue Connection Requests currently. TODO */ - error_report("%s: unexpected Connection Response (%02x) " - "packet, ignoring.", __func__, id); - break; - - case L2CAP_CONF_REQ: - if (unlikely(len < L2CAP_CONF_REQ_SIZE(0))) { - err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; - goto reject; - } - - l2cap_channel_config_req_msg(l2cap, - le16_to_cpu(((l2cap_conf_req *) params)->flags) & 1, - le16_to_cpu(((l2cap_conf_req *) params)->dcid), - ((l2cap_conf_req *) params)->data, - len - L2CAP_CONF_REQ_SIZE(0)); - break; - - case L2CAP_CONF_RSP: - if (unlikely(len < L2CAP_CONF_RSP_SIZE(0))) { - err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; - goto reject; - } - - if (l2cap_channel_config_rsp_msg(l2cap, - le16_to_cpu(((l2cap_conf_rsp *) params)->result), - le16_to_cpu(((l2cap_conf_rsp *) params)->flags) & 1, - le16_to_cpu(((l2cap_conf_rsp *) params)->scid), - ((l2cap_conf_rsp *) params)->data, - len - L2CAP_CONF_RSP_SIZE(0))) - error_report("%s: unexpected Configure Response (%02x) " - "packet, ignoring.", __func__, id); - break; - - case L2CAP_DISCONN_REQ: - if (unlikely(len != L2CAP_DISCONN_REQ_SIZE)) { - err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; - goto reject; - } - - l2cap_channel_close(l2cap, - le16_to_cpu(((l2cap_disconn_req *) params)->dcid), - le16_to_cpu(((l2cap_disconn_req *) params)->scid)); - break; - - case L2CAP_DISCONN_RSP: - if (unlikely(len != L2CAP_DISCONN_RSP_SIZE)) { - err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; - goto reject; - } - - /* We never issue Disconnection Requests currently. TODO */ - error_report("%s: unexpected Disconnection Response (%02x) " - "packet, ignoring.", __func__, id); - break; - - case L2CAP_ECHO_REQ: - l2cap_echo_response(l2cap, params, len); - break; - - case L2CAP_ECHO_RSP: - /* We never issue Echo Requests currently. TODO */ - error_report("%s: unexpected Echo Response (%02x) " - "packet, ignoring.", __func__, id); - break; - - case L2CAP_INFO_REQ: - if (unlikely(len != L2CAP_INFO_REQ_SIZE)) { - err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; - goto reject; - } - - l2cap_info(l2cap, le16_to_cpu(((l2cap_info_req *) params)->type)); - break; - - case L2CAP_INFO_RSP: - if (unlikely(len != L2CAP_INFO_RSP_SIZE)) { - err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; - goto reject; - } - - /* We never issue Information Requests currently. TODO */ - error_report("%s: unexpected Information Response (%02x) " - "packet, ignoring.", __func__, id); - break; - - default: - err = L2CAP_REJ_CMD_NOT_UNDERSTOOD; - reject: - l2cap_command_reject(l2cap, id, err, 0, 0); - break; - } -} - -static void l2cap_rexmit_enable(struct l2cap_chan_s *ch, int enable) -{ - ch->rexmit = enable; - - l2cap_retransmission_timer_update(ch); - l2cap_monitor_timer_update(ch); -} - -/* Command frame SDU */ -static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len) -{ - struct l2cap_instance_s *l2cap = opaque; - const l2cap_cmd_hdr *hdr; - int clen; - - while (len) { - hdr = (void *) data; - if (len < L2CAP_CMD_HDR_SIZE) - /* TODO: signal an error */ - return; - len -= L2CAP_CMD_HDR_SIZE; - data += L2CAP_CMD_HDR_SIZE; - - clen = le16_to_cpu(hdr->len); - if (len < clen) { - l2cap_command_reject(l2cap, hdr->ident, - L2CAP_REJ_CMD_NOT_UNDERSTOOD, 0, 0); - break; - } - - l2cap_command(l2cap, hdr->code, hdr->ident, data, clen); - len -= clen; - data += clen; - } -} - -/* Group frame SDU */ -static void l2cap_gframe_in(void *opaque, const uint8_t *data, int len) -{ -} - -/* Supervisory frame */ -static void l2cap_sframe_in(struct l2cap_chan_s *ch, uint16_t ctrl) -{ -} - -/* Basic L2CAP mode Information frame */ -static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, - const l2cap_hdr *hdr, int len) -{ - /* We have a full SDU, no further processing */ - ch->params.sdu_in(ch->params.opaque, hdr->data, len); -} - -/* Flow Control and Retransmission mode frame */ -static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, - const l2cap_hdr *hdr, int len) -{ - uint16_t fcs = lduw_le_p(hdr->data + len - 2); - - if (len < 4) - goto len_error; - if (l2cap_fcs16((const uint8_t *) hdr, L2CAP_HDR_SIZE + len - 2) != fcs) - goto fcs_error; - - if ((hdr->data[0] >> 7) == ch->rexmit) - l2cap_rexmit_enable(ch, !(hdr->data[0] >> 7)); - - if (hdr->data[0] & 1) { - if (len != 4) { - /* TODO: Signal an error? */ - return; - } - l2cap_sframe_in(ch, lduw_le_p(hdr->data)); - return; - } - - switch (hdr->data[1] >> 6) { /* SAR */ - case L2CAP_SAR_NO_SEG: - if (ch->len_total) - goto seg_error; - if (len - 4 > ch->mps) - goto len_error; - - ch->params.sdu_in(ch->params.opaque, hdr->data + 2, len - 4); - break; - - case L2CAP_SAR_START: - if (ch->len_total || len < 6) - goto seg_error; - if (len - 6 > ch->mps) - goto len_error; - - ch->len_total = lduw_le_p(hdr->data + 2); - if (len >= 6 + ch->len_total) - goto seg_error; - - ch->len_cur = len - 6; - memcpy(ch->sdu, hdr->data + 4, ch->len_cur); - break; - - case L2CAP_SAR_END: - if (!ch->len_total || ch->len_cur + len - 4 < ch->len_total) - goto seg_error; - if (len - 4 > ch->mps) - goto len_error; - - memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4); - ch->params.sdu_in(ch->params.opaque, ch->sdu, ch->len_total); - break; - - case L2CAP_SAR_CONT: - if (!ch->len_total || ch->len_cur + len - 4 >= ch->len_total) - goto seg_error; - if (len - 4 > ch->mps) - goto len_error; - - memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4); - ch->len_cur += len - 4; - break; - - seg_error: - len_error: /* TODO */ - fcs_error: /* TODO */ - ch->len_cur = 0; - ch->len_total = 0; - break; - } -} - -static void l2cap_frame_in(struct l2cap_instance_s *l2cap, - const l2cap_hdr *frame) -{ - uint16_t cid = le16_to_cpu(frame->cid); - uint16_t len = le16_to_cpu(frame->len); - - if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) { - error_report("%s: frame addressed to a non-existent L2CAP " - "channel %04x received.", __func__, cid); - return; - } - - l2cap->cid[cid]->frame_in(l2cap->cid[cid], cid, frame, len); -} - -/* "Recombination" */ -static void l2cap_pdu_in(struct l2cap_instance_s *l2cap, - const uint8_t *data, int len) -{ - const l2cap_hdr *hdr = (void *) l2cap->frame_in; - - if (unlikely(len + l2cap->frame_in_len > sizeof(l2cap->frame_in))) { - if (l2cap->frame_in_len < sizeof(l2cap->frame_in)) { - memcpy(l2cap->frame_in + l2cap->frame_in_len, data, - sizeof(l2cap->frame_in) - l2cap->frame_in_len); - l2cap->frame_in_len = sizeof(l2cap->frame_in); - /* TODO: truncate */ - l2cap_frame_in(l2cap, hdr); - } - - return; - } - - memcpy(l2cap->frame_in + l2cap->frame_in_len, data, len); - l2cap->frame_in_len += len; - - if (len >= L2CAP_HDR_SIZE) - if (len >= L2CAP_HDR_SIZE + le16_to_cpu(hdr->len)) - l2cap_frame_in(l2cap, hdr); - /* There is never a start of a new PDU in the same ACL packet, so - * no need to memmove the remaining payload and loop. */ -} - -static inline uint8_t *l2cap_pdu_out(struct l2cap_instance_s *l2cap, - uint16_t cid, uint16_t len) -{ - l2cap_hdr *hdr = (void *) l2cap->frame_out; - - l2cap->frame_out_len = len + L2CAP_HDR_SIZE; - - hdr->cid = cpu_to_le16(cid); - hdr->len = cpu_to_le16(len); - - return l2cap->frame_out + L2CAP_HDR_SIZE; -} - -static inline void l2cap_pdu_submit(struct l2cap_instance_s *l2cap) -{ - /* TODO: Fragmentation */ - (l2cap->role ? - l2cap->link->slave->lmp_acl_data : l2cap->link->host->lmp_acl_resp) - (l2cap->link, l2cap->frame_out, 1, l2cap->frame_out_len); -} - -static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len) -{ - struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm; - - if (len > chan->params.remote_mtu) { - error_report("%s: B-Frame for CID %04x longer than %i octets.", - __func__, - chan->remote_cid, chan->params.remote_mtu); - exit(-1); - } - - return l2cap_pdu_out(chan->l2cap, chan->remote_cid, len); -} - -static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms) -{ - struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parms; - - l2cap_pdu_submit(chan->l2cap); -} - -#if 0 -/* Stub: Only used if an emulated device requests outgoing flow control */ -static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len) -{ - struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm; - - if (len > chan->params.remote_mtu) { - /* TODO: slice into segments and queue each segment as a separate - * I-Frame in a FIFO of I-Frames, local to the CID. */ - } else { - /* TODO: add to the FIFO of I-Frames, local to the CID. */ - /* Possibly we need to return a pointer to a contiguous buffer - * for now and then memcpy from it into FIFOs in l2cap_iframe_submit - * while segmenting at the same time. */ - } - return 0; -} - -static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm) -{ - /* TODO: If flow control indicates clear to send, start submitting the - * invidual I-Frames from the FIFO, but don't remove them from there. - * Kick the appropriate timer until we get an S-Frame, and only then - * remove from FIFO or resubmit and re-kick the timer if the timer - * expired. */ -} -#endif - -static void l2cap_init(struct l2cap_instance_s *l2cap, - struct bt_link_s *link, int role) -{ - l2cap->link = link; - l2cap->role = role; - l2cap->dev = (struct bt_l2cap_device_s *) - (role ? link->host : link->slave); - - l2cap->next_id = 1; - - /* Establish the signalling channel */ - l2cap->signalling_ch.params.sdu_in = l2cap_cframe_in; - l2cap->signalling_ch.params.sdu_out = l2cap_bframe_out; - l2cap->signalling_ch.params.sdu_submit = l2cap_bframe_submit; - l2cap->signalling_ch.params.opaque = l2cap; - l2cap->signalling_ch.params.remote_mtu = 48; - l2cap->signalling_ch.remote_cid = L2CAP_CID_SIGNALLING; - l2cap->signalling_ch.frame_in = l2cap_bframe_in; - l2cap->signalling_ch.mps = 65536; - l2cap->signalling_ch.min_mtu = 48; - l2cap->signalling_ch.mode = L2CAP_MODE_BASIC; - l2cap->signalling_ch.l2cap = l2cap; - l2cap->cid[L2CAP_CID_SIGNALLING] = &l2cap->signalling_ch; - - /* Establish the connection-less data channel */ - l2cap->group_ch.params.sdu_in = l2cap_gframe_in; - l2cap->group_ch.params.opaque = l2cap; - l2cap->group_ch.frame_in = l2cap_bframe_in; - l2cap->group_ch.mps = 65533; - l2cap->group_ch.l2cap = l2cap; - l2cap->group_ch.remote_cid = L2CAP_CID_INVALID; - l2cap->cid[L2CAP_CID_GROUP] = &l2cap->group_ch; -} - -static void l2cap_teardown(struct l2cap_instance_s *l2cap, int send_disconnect) -{ - int cid; - - /* Don't send DISCONNECT if we are currently handling a DISCONNECT - * sent from the other side. */ - if (send_disconnect) { - if (l2cap->role) - l2cap->dev->device.lmp_disconnect_slave(l2cap->link); - /* l2cap->link is invalid from now on. */ - else - l2cap->dev->device.lmp_disconnect_master(l2cap->link); - } - - for (cid = L2CAP_CID_ALLOC; cid < L2CAP_CID_MAX; cid ++) - if (l2cap->cid[cid]) { - l2cap->cid[cid]->params.close(l2cap->cid[cid]->params.opaque); - g_free(l2cap->cid[cid]); - } - - if (l2cap->role) - g_free(l2cap); - else - g_free(l2cap->link); -} - -/* L2CAP glue to lower layers in bluetooth stack (LMP) */ - -static void l2cap_lmp_connection_request(struct bt_link_s *link) -{ - struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->slave; - struct slave_l2cap_instance_s *l2cap; - - /* Always accept - we only get called if (dev->device->page_scan). */ - - l2cap = g_malloc0(sizeof(struct slave_l2cap_instance_s)); - l2cap->link.slave = &dev->device; - l2cap->link.host = link->host; - l2cap_init(&l2cap->l2cap, &l2cap->link, 0); - - /* Always at the end */ - link->host->reject_reason = 0; - link->host->lmp_connection_complete(&l2cap->link); -} - -/* Stub */ -static void l2cap_lmp_connection_complete(struct bt_link_s *link) -{ - struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host; - struct l2cap_instance_s *l2cap; - - if (dev->device.reject_reason) { - /* Signal to upper layer */ - return; - } - - l2cap = g_malloc0(sizeof(struct l2cap_instance_s)); - l2cap_init(l2cap, link, 1); - - link->acl_mode = acl_active; - - /* Signal to upper layer */ -} - -/* Stub */ -static void l2cap_lmp_disconnect_host(struct bt_link_s *link) -{ - struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host; - struct l2cap_instance_s *l2cap = - /* TODO: Retrieve from upper layer */ (void *) dev; - - /* Signal to upper layer */ - - l2cap_teardown(l2cap, 0); -} - -static void l2cap_lmp_disconnect_slave(struct bt_link_s *link) -{ - struct slave_l2cap_instance_s *l2cap = - (struct slave_l2cap_instance_s *) link; - - l2cap_teardown(&l2cap->l2cap, 0); -} - -static void l2cap_lmp_acl_data_slave(struct bt_link_s *link, - const uint8_t *data, int start, int len) -{ - struct slave_l2cap_instance_s *l2cap = - (struct slave_l2cap_instance_s *) link; - - if (start) - l2cap->l2cap.frame_in_len = 0; - - l2cap_pdu_in(&l2cap->l2cap, data, len); -} - -/* Stub */ -static void l2cap_lmp_acl_data_host(struct bt_link_s *link, - const uint8_t *data, int start, int len) -{ - struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host; - struct l2cap_instance_s *l2cap = - /* TODO: Retrieve from upper layer */ (void *) dev; - - if (start) - l2cap->frame_in_len = 0; - - l2cap_pdu_in(l2cap, data, len); -} - -static void l2cap_dummy_destroy(struct bt_device_s *dev) -{ - struct bt_l2cap_device_s *l2cap_dev = (struct bt_l2cap_device_s *) dev; - - bt_l2cap_device_done(l2cap_dev); -} - -void bt_l2cap_device_init(struct bt_l2cap_device_s *dev, - struct bt_scatternet_s *net) -{ - bt_device_init(&dev->device, net); - - dev->device.lmp_connection_request = l2cap_lmp_connection_request; - dev->device.lmp_connection_complete = l2cap_lmp_connection_complete; - dev->device.lmp_disconnect_master = l2cap_lmp_disconnect_host; - dev->device.lmp_disconnect_slave = l2cap_lmp_disconnect_slave; - dev->device.lmp_acl_data = l2cap_lmp_acl_data_slave; - dev->device.lmp_acl_resp = l2cap_lmp_acl_data_host; - - dev->device.handle_destroy = l2cap_dummy_destroy; -} - -void bt_l2cap_device_done(struct bt_l2cap_device_s *dev) -{ - bt_device_done(&dev->device); - - /* Should keep a list of all instances and go through it and - * invoke l2cap_teardown() for each. */ -} - -void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm, int min_mtu, - int (*new_channel)(struct bt_l2cap_device_s *dev, - struct bt_l2cap_conn_params_s *params)) -{ - struct bt_l2cap_psm_s *new_psm = l2cap_psm(dev, psm); - - if (new_psm) { - error_report("%s: PSM %04x already registered for device `%s'.", - __func__, psm, dev->device.lmp_name); - exit(-1); - } - - new_psm = g_malloc0(sizeof(*new_psm)); - new_psm->psm = psm; - new_psm->min_mtu = min_mtu; - new_psm->new_channel = new_channel; - new_psm->next = dev->first_psm; - dev->first_psm = new_psm; -} diff --git a/hw/bt/sdp.c b/hw/bt/sdp.c deleted file mode 100644 index 2860d76c85..0000000000 --- a/hw/bt/sdp.c +++ /dev/null @@ -1,989 +0,0 @@ -/* - * Service Discover Protocol server for QEMU L2CAP devices - * - * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "qemu/host-utils.h" -#include "hw/bt.h" - -struct bt_l2cap_sdp_state_s { - struct bt_l2cap_conn_params_s *channel; - - struct sdp_service_record_s { - int match; - - int *uuid; - int uuids; - struct sdp_service_attribute_s { - int match; - - int attribute_id; - int len; - void *pair; - } *attribute_list; - int attributes; - } *service_list; - int services; -}; - -static ssize_t sdp_datalen(const uint8_t **element, ssize_t *left) -{ - uint32_t len = *(*element) ++ & SDP_DSIZE_MASK; - - if (!*left) - return -1; - (*left) --; - - if (len < SDP_DSIZE_NEXT1) - return 1 << len; - else if (len == SDP_DSIZE_NEXT1) { - if (*left < 1) - return -1; - (*left) --; - - return *(*element) ++; - } else if (len == SDP_DSIZE_NEXT2) { - if (*left < 2) - return -1; - (*left) -= 2; - - len = (*(*element) ++) << 8; - return len | (*(*element) ++); - } else { - if (*left < 4) - return -1; - (*left) -= 4; - - len = (*(*element) ++) << 24; - len |= (*(*element) ++) << 16; - len |= (*(*element) ++) << 8; - return len | (*(*element) ++); - } -} - -static const uint8_t bt_base_uuid[12] = { - 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, -}; - -static int sdp_uuid_match(struct sdp_service_record_s *record, - const uint8_t *uuid, ssize_t datalen) -{ - int *lo, hi, val; - - if (datalen == 16 || datalen == 4) { - if (datalen == 16 && memcmp(uuid + 4, bt_base_uuid, 12)) - return 0; - - if (uuid[0] | uuid[1]) - return 0; - uuid += 2; - } - - val = (uuid[0] << 8) | uuid[1]; - lo = record->uuid; - hi = record->uuids; - while (hi >>= 1) - if (lo[hi] <= val) - lo += hi; - - return *lo == val; -} - -#define CONTINUATION_PARAM_SIZE (1 + sizeof(int)) -#define MAX_PDU_OUT_SIZE 96 /* Arbitrary */ -#define PDU_HEADER_SIZE 5 -#define MAX_RSP_PARAM_SIZE (MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE - \ - CONTINUATION_PARAM_SIZE) - -static int sdp_svc_match(struct bt_l2cap_sdp_state_s *sdp, - const uint8_t **req, ssize_t *len) -{ - size_t datalen; - int i; - - if ((**req & ~SDP_DSIZE_MASK) != SDP_DTYPE_UUID) - return 1; - - datalen = sdp_datalen(req, len); - if (datalen != 2 && datalen != 4 && datalen != 16) - return 1; - - for (i = 0; i < sdp->services; i ++) - if (sdp_uuid_match(&sdp->service_list[i], *req, datalen)) - sdp->service_list[i].match = 1; - - (*req) += datalen; - (*len) -= datalen; - - return 0; -} - -static ssize_t sdp_svc_search(struct bt_l2cap_sdp_state_s *sdp, - uint8_t *rsp, const uint8_t *req, ssize_t len) -{ - ssize_t seqlen; - int i, count, start, end, max; - int32_t handle; - - /* Perform the search */ - for (i = 0; i < sdp->services; i ++) - sdp->service_list[i].match = 0; - - if (len < 1) - return -SDP_INVALID_SYNTAX; - if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) { - seqlen = sdp_datalen(&req, &len); - if (seqlen < 3 || len < seqlen) - return -SDP_INVALID_SYNTAX; - len -= seqlen; - while (seqlen) - if (sdp_svc_match(sdp, &req, &seqlen)) - return -SDP_INVALID_SYNTAX; - } else { - if (sdp_svc_match(sdp, &req, &len)) { - return -SDP_INVALID_SYNTAX; - } - } - - if (len < 3) - return -SDP_INVALID_SYNTAX; - max = (req[0] << 8) | req[1]; - req += 2; - len -= 2; - - if (*req) { - if (len <= sizeof(int)) - return -SDP_INVALID_SYNTAX; - len -= sizeof(int); - memcpy(&start, req + 1, sizeof(int)); - } else - start = 0; - - if (len > 1) - return -SDP_INVALID_SYNTAX; - - /* Output the results */ - len = 4; - count = 0; - end = start; - for (i = 0; i < sdp->services; i ++) - if (sdp->service_list[i].match) { - if (count >= start && count < max && len + 4 < MAX_RSP_PARAM_SIZE) { - handle = i; - memcpy(rsp + len, &handle, 4); - len += 4; - end = count + 1; - } - - count ++; - } - - rsp[0] = count >> 8; - rsp[1] = count & 0xff; - rsp[2] = (end - start) >> 8; - rsp[3] = (end - start) & 0xff; - - if (end < count) { - rsp[len ++] = sizeof(int); - memcpy(rsp + len, &end, sizeof(int)); - len += 4; - } else - rsp[len ++] = 0; - - return len; -} - -static int sdp_attr_match(struct sdp_service_record_s *record, - const uint8_t **req, ssize_t *len) -{ - int i, start, end; - - if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) { - (*req) ++; - if (*len < 3) - return 1; - - start = (*(*req) ++) << 8; - start |= *(*req) ++; - end = start; - *len -= 3; - } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) { - (*req) ++; - if (*len < 5) - return 1; - - start = (*(*req) ++) << 8; - start |= *(*req) ++; - end = (*(*req) ++) << 8; - end |= *(*req) ++; - *len -= 5; - } else - return 1; - - for (i = 0; i < record->attributes; i ++) - if (record->attribute_list[i].attribute_id >= start && - record->attribute_list[i].attribute_id <= end) - record->attribute_list[i].match = 1; - - return 0; -} - -static ssize_t sdp_attr_get(struct bt_l2cap_sdp_state_s *sdp, - uint8_t *rsp, const uint8_t *req, ssize_t len) -{ - ssize_t seqlen; - int i, start, end, max; - int32_t handle; - struct sdp_service_record_s *record; - uint8_t *lst; - - /* Perform the search */ - if (len < 7) - return -SDP_INVALID_SYNTAX; - memcpy(&handle, req, 4); - req += 4; - len -= 4; - - if (handle < 0 || handle > sdp->services) - return -SDP_INVALID_RECORD_HANDLE; - record = &sdp->service_list[handle]; - - for (i = 0; i < record->attributes; i ++) - record->attribute_list[i].match = 0; - - max = (req[0] << 8) | req[1]; - req += 2; - len -= 2; - if (max < 0x0007) - return -SDP_INVALID_SYNTAX; - - if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) { - seqlen = sdp_datalen(&req, &len); - if (seqlen < 3 || len < seqlen) - return -SDP_INVALID_SYNTAX; - len -= seqlen; - - while (seqlen) - if (sdp_attr_match(record, &req, &seqlen)) - return -SDP_INVALID_SYNTAX; - } else { - if (sdp_attr_match(record, &req, &len)) { - return -SDP_INVALID_SYNTAX; - } - } - - if (len < 1) - return -SDP_INVALID_SYNTAX; - - if (*req) { - if (len <= sizeof(int)) - return -SDP_INVALID_SYNTAX; - len -= sizeof(int); - memcpy(&start, req + 1, sizeof(int)); - } else - start = 0; - - if (len > 1) - return -SDP_INVALID_SYNTAX; - - /* Output the results */ - lst = rsp + 2; - max = MIN(max, MAX_RSP_PARAM_SIZE); - len = 3 - start; - end = 0; - for (i = 0; i < record->attributes; i ++) - if (record->attribute_list[i].match) { - if (len >= 0 && len + record->attribute_list[i].len < max) { - memcpy(lst + len, record->attribute_list[i].pair, - record->attribute_list[i].len); - end = len + record->attribute_list[i].len; - } - len += record->attribute_list[i].len; - } - if (0 >= start) { - lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2; - lst[1] = (len + start - 3) >> 8; - lst[2] = (len + start - 3) & 0xff; - } - - rsp[0] = end >> 8; - rsp[1] = end & 0xff; - - if (end < len) { - len = end + start; - lst[end ++] = sizeof(int); - memcpy(lst + end, &len, sizeof(int)); - end += sizeof(int); - } else - lst[end ++] = 0; - - return end + 2; -} - -static int sdp_svc_attr_match(struct bt_l2cap_sdp_state_s *sdp, - const uint8_t **req, ssize_t *len) -{ - int i, j, start, end; - struct sdp_service_record_s *record; - - if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) { - (*req) ++; - if (*len < 3) - return 1; - - start = (*(*req) ++) << 8; - start |= *(*req) ++; - end = start; - *len -= 3; - } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) { - (*req) ++; - if (*len < 5) - return 1; - - start = (*(*req) ++) << 8; - start |= *(*req) ++; - end = (*(*req) ++) << 8; - end |= *(*req) ++; - *len -= 5; - } else - return 1; - - for (i = 0; i < sdp->services; i ++) - if ((record = &sdp->service_list[i])->match) - for (j = 0; j < record->attributes; j ++) - if (record->attribute_list[j].attribute_id >= start && - record->attribute_list[j].attribute_id <= end) - record->attribute_list[j].match = 1; - - return 0; -} - -static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp, - uint8_t *rsp, const uint8_t *req, ssize_t len) -{ - ssize_t seqlen; - int i, j, start, end, max; - struct sdp_service_record_s *record; - uint8_t *lst; - - /* Perform the search */ - for (i = 0; i < sdp->services; i ++) { - sdp->service_list[i].match = 0; - for (j = 0; j < sdp->service_list[i].attributes; j ++) - sdp->service_list[i].attribute_list[j].match = 0; - } - - if (len < 1) - return -SDP_INVALID_SYNTAX; - if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) { - seqlen = sdp_datalen(&req, &len); - if (seqlen < 3 || len < seqlen) - return -SDP_INVALID_SYNTAX; - len -= seqlen; - - while (seqlen) - if (sdp_svc_match(sdp, &req, &seqlen)) - return -SDP_INVALID_SYNTAX; - } else { - if (sdp_svc_match(sdp, &req, &len)) { - return -SDP_INVALID_SYNTAX; - } - } - - if (len < 3) - return -SDP_INVALID_SYNTAX; - max = (req[0] << 8) | req[1]; - req += 2; - len -= 2; - if (max < 0x0007) - return -SDP_INVALID_SYNTAX; - - if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) { - seqlen = sdp_datalen(&req, &len); - if (seqlen < 3 || len < seqlen) - return -SDP_INVALID_SYNTAX; - len -= seqlen; - - while (seqlen) - if (sdp_svc_attr_match(sdp, &req, &seqlen)) - return -SDP_INVALID_SYNTAX; - } else { - if (sdp_svc_attr_match(sdp, &req, &len)) { - return -SDP_INVALID_SYNTAX; - } - } - - if (len < 1) - return -SDP_INVALID_SYNTAX; - - if (*req) { - if (len <= sizeof(int)) - return -SDP_INVALID_SYNTAX; - len -= sizeof(int); - memcpy(&start, req + 1, sizeof(int)); - } else - start = 0; - - if (len > 1) - return -SDP_INVALID_SYNTAX; - - /* Output the results */ - /* This assumes empty attribute lists are never to be returned even - * for matching Service Records. In practice this shouldn't happen - * as the requestor will usually include the always present - * ServiceRecordHandle AttributeID in AttributeIDList. */ - lst = rsp + 2; - max = MIN(max, MAX_RSP_PARAM_SIZE); - len = 3 - start; - end = 0; - for (i = 0; i < sdp->services; i ++) - if ((record = &sdp->service_list[i])->match) { - len += 3; - seqlen = len; - for (j = 0; j < record->attributes; j ++) - if (record->attribute_list[j].match) { - if (len >= 0) - if (len + record->attribute_list[j].len < max) { - memcpy(lst + len, record->attribute_list[j].pair, - record->attribute_list[j].len); - end = len + record->attribute_list[j].len; - } - len += record->attribute_list[j].len; - } - if (seqlen == len) - len -= 3; - else if (seqlen >= 3 && seqlen < max) { - lst[seqlen - 3] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2; - lst[seqlen - 2] = (len - seqlen) >> 8; - lst[seqlen - 1] = (len - seqlen) & 0xff; - } - } - if (len == 3 - start) - len -= 3; - else if (0 >= start) { - lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2; - lst[1] = (len + start - 3) >> 8; - lst[2] = (len + start - 3) & 0xff; - } - - rsp[0] = end >> 8; - rsp[1] = end & 0xff; - - if (end < len) { - len = end + start; - lst[end ++] = sizeof(int); - memcpy(lst + end, &len, sizeof(int)); - end += sizeof(int); - } else - lst[end ++] = 0; - - return end + 2; -} - -static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len) -{ - struct bt_l2cap_sdp_state_s *sdp = opaque; - enum bt_sdp_cmd pdu_id; - uint8_t rsp[MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE], *sdu_out; - int transaction_id, plen; - int err = 0; - int rsp_len = 0; - - if (len < 5) { - error_report("%s: short SDP PDU (%iB).", __func__, len); - return; - } - - pdu_id = *data ++; - transaction_id = (data[0] << 8) | data[1]; - plen = (data[2] << 8) | data[3]; - data += 4; - len -= 5; - - if (len != plen) { - error_report("%s: wrong SDP PDU length (%iB != %iB).", - __func__, plen, len); - err = SDP_INVALID_PDU_SIZE; - goto respond; - } - - switch (pdu_id) { - case SDP_SVC_SEARCH_REQ: - rsp_len = sdp_svc_search(sdp, rsp, data, len); - pdu_id = SDP_SVC_SEARCH_RSP; - break; - - case SDP_SVC_ATTR_REQ: - rsp_len = sdp_attr_get(sdp, rsp, data, len); - pdu_id = SDP_SVC_ATTR_RSP; - break; - - case SDP_SVC_SEARCH_ATTR_REQ: - rsp_len = sdp_svc_search_attr_get(sdp, rsp, data, len); - pdu_id = SDP_SVC_SEARCH_ATTR_RSP; - break; - - case SDP_ERROR_RSP: - case SDP_SVC_ATTR_RSP: - case SDP_SVC_SEARCH_RSP: - case SDP_SVC_SEARCH_ATTR_RSP: - default: - error_report("%s: unexpected SDP PDU ID %02x.", - __func__, pdu_id); - err = SDP_INVALID_SYNTAX; - break; - } - - if (rsp_len < 0) { - err = -rsp_len; - rsp_len = 0; - } - -respond: - if (err) { - pdu_id = SDP_ERROR_RSP; - rsp[rsp_len ++] = err >> 8; - rsp[rsp_len ++] = err & 0xff; - } - - sdu_out = sdp->channel->sdu_out(sdp->channel, rsp_len + PDU_HEADER_SIZE); - - sdu_out[0] = pdu_id; - sdu_out[1] = transaction_id >> 8; - sdu_out[2] = transaction_id & 0xff; - sdu_out[3] = rsp_len >> 8; - sdu_out[4] = rsp_len & 0xff; - memcpy(sdu_out + PDU_HEADER_SIZE, rsp, rsp_len); - - sdp->channel->sdu_submit(sdp->channel); -} - -static void bt_l2cap_sdp_close_ch(void *opaque) -{ - struct bt_l2cap_sdp_state_s *sdp = opaque; - int i; - - for (i = 0; i < sdp->services; i ++) { - g_free(sdp->service_list[i].attribute_list[0].pair); - g_free(sdp->service_list[i].attribute_list); - g_free(sdp->service_list[i].uuid); - } - g_free(sdp->service_list); - g_free(sdp); -} - -struct sdp_def_service_s { - uint16_t class_uuid; - struct sdp_def_attribute_s { - uint16_t id; - struct sdp_def_data_element_s { - uint8_t type; - union { - uint32_t uint; - const char *str; - struct sdp_def_data_element_s *list; - } value; - } data; - } attributes[]; -}; - -/* Calculate a safe byte count to allocate that will store the given - * element, at the same time count elements of a UUID type. */ -static int sdp_attr_max_size(struct sdp_def_data_element_s *element, - int *uuids) -{ - int type = element->type & ~SDP_DSIZE_MASK; - int len; - - if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_UUID || - type == SDP_DTYPE_BOOL) { - if (type == SDP_DTYPE_UUID) - (*uuids) ++; - return 1 + (1 << (element->type & SDP_DSIZE_MASK)); - } - - if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) { - if (element->type & SDP_DSIZE_MASK) { - for (len = 0; element->value.str[len] | - element->value.str[len + 1]; len ++); - return len; - } else - return 2 + strlen(element->value.str); - } - - if (type != SDP_DTYPE_SEQ) - exit(-1); - len = 2; - element = element->value.list; - while (element->type) - len += sdp_attr_max_size(element ++, uuids); - if (len > 255) - exit (-1); - - return len; -} - -static int sdp_attr_write(uint8_t *data, - struct sdp_def_data_element_s *element, int **uuid) -{ - int type = element->type & ~SDP_DSIZE_MASK; - int len = 0; - - if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_BOOL) { - data[len ++] = element->type; - if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_1) - data[len ++] = (element->value.uint >> 0) & 0xff; - else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_2) { - data[len ++] = (element->value.uint >> 8) & 0xff; - data[len ++] = (element->value.uint >> 0) & 0xff; - } else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_4) { - data[len ++] = (element->value.uint >> 24) & 0xff; - data[len ++] = (element->value.uint >> 16) & 0xff; - data[len ++] = (element->value.uint >> 8) & 0xff; - data[len ++] = (element->value.uint >> 0) & 0xff; - } - - return len; - } - - if (type == SDP_DTYPE_UUID) { - *(*uuid) ++ = element->value.uint; - - data[len ++] = element->type; - data[len ++] = (element->value.uint >> 24) & 0xff; - data[len ++] = (element->value.uint >> 16) & 0xff; - data[len ++] = (element->value.uint >> 8) & 0xff; - data[len ++] = (element->value.uint >> 0) & 0xff; - memcpy(data + len, bt_base_uuid, 12); - - return len + 12; - } - - data[0] = type | SDP_DSIZE_NEXT1; - if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) { - if (element->type & SDP_DSIZE_MASK) - for (len = 0; element->value.str[len] | - element->value.str[len + 1]; len ++); - else - len = strlen(element->value.str); - memcpy(data + 2, element->value.str, data[1] = len); - - return len + 2; - } - - len = 2; - element = element->value.list; - while (element->type) - len += sdp_attr_write(data + len, element ++, uuid); - data[1] = len - 2; - - return len; -} - -static int sdp_attributeid_compare(const struct sdp_service_attribute_s *a, - const struct sdp_service_attribute_s *b) -{ - return (int) b->attribute_id - a->attribute_id; -} - -static int sdp_uuid_compare(const int *a, const int *b) -{ - return *a - *b; -} - -static void sdp_service_record_build(struct sdp_service_record_s *record, - struct sdp_def_service_s *def, int handle) -{ - int len = 0; - uint8_t *data; - int *uuid; - - record->uuids = 0; - while (def->attributes[record->attributes].data.type) { - len += 3; - len += sdp_attr_max_size(&def->attributes[record->attributes ++].data, - &record->uuids); - } - - assert(len > 0); - record->uuids = pow2ceil(record->uuids); - record->attribute_list = - g_malloc0(record->attributes * sizeof(*record->attribute_list)); - record->uuid = - g_malloc0(record->uuids * sizeof(*record->uuid)); - data = g_malloc(len); - - record->attributes = 0; - uuid = record->uuid; - while (def->attributes[record->attributes].data.type) { - int attribute_id = def->attributes[record->attributes].id; - record->attribute_list[record->attributes].pair = data; - record->attribute_list[record->attributes].attribute_id = attribute_id; - - len = 0; - data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2; - data[len ++] = attribute_id >> 8; - data[len ++] = attribute_id & 0xff; - len += sdp_attr_write(data + len, - &def->attributes[record->attributes].data, &uuid); - - /* Special case: assign a ServiceRecordHandle in sequence */ - if (def->attributes[record->attributes].id == SDP_ATTR_RECORD_HANDLE) - def->attributes[record->attributes].data.value.uint = handle; - /* Note: we could also assign a ServiceDescription based on - * sdp->device.device->lmp_name. */ - - record->attribute_list[record->attributes ++].len = len; - data += len; - } - - /* Sort the attribute list by the AttributeID. The first must be - * SDP_ATTR_RECORD_HANDLE so that bt_l2cap_sdp_close_ch can free - * the buffer. - */ - qsort(record->attribute_list, record->attributes, - sizeof(*record->attribute_list), - (void *) sdp_attributeid_compare); - assert(record->attribute_list[0].pair == data); - - /* Sort the searchable UUIDs list for bisection */ - qsort(record->uuid, record->uuids, - sizeof(*record->uuid), - (void *) sdp_uuid_compare); -} - -static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp, - struct sdp_def_service_s **service) -{ - sdp->services = 0; - while (service[sdp->services]) - sdp->services ++; - sdp->service_list = - g_malloc0(sdp->services * sizeof(*sdp->service_list)); - - sdp->services = 0; - while (*service) { - sdp_service_record_build(&sdp->service_list[sdp->services], - *service, sdp->services); - service ++; - sdp->services ++; - } -} - -#define LAST { .type = 0 } -#define SERVICE(name, attrs) \ - static struct sdp_def_service_s glue(glue(sdp_service_, name), _s) = { \ - .attributes = { attrs { .data = LAST } }, \ - }; -#define ATTRIBUTE(attrid, val) { .id = glue(SDP_ATTR_, attrid), .data = val }, -#define UINT8(val) { \ - .type = SDP_DTYPE_UINT | SDP_DSIZE_1, \ - .value.uint = val, \ - }, -#define UINT16(val) { \ - .type = SDP_DTYPE_UINT | SDP_DSIZE_2, \ - .value.uint = val, \ - }, -#define UINT32(val) { \ - .type = SDP_DTYPE_UINT | SDP_DSIZE_4, \ - .value.uint = val, \ - }, -#define UUID128(val) { \ - .type = SDP_DTYPE_UUID | SDP_DSIZE_16, \ - .value.uint = val, \ - }, -#define SDP_TRUE { \ - .type = SDP_DTYPE_BOOL | SDP_DSIZE_1, \ - .value.uint = 1, \ - }, -#define SDP_FALSE { \ - .type = SDP_DTYPE_BOOL | SDP_DSIZE_1, \ - .value.uint = 0, \ - }, -#define STRING(val) { \ - .type = SDP_DTYPE_STRING, \ - .value.str = val, \ - }, -#define ARRAY(...) { \ - .type = SDP_DTYPE_STRING | SDP_DSIZE_2, \ - .value.str = (char []) { __VA_ARGS__, 0, 0 }, \ - }, -#define URL(val) { \ - .type = SDP_DTYPE_URL, \ - .value.str = val, \ - }, -#if 1 -#define LIST(val) { \ - .type = SDP_DTYPE_SEQ, \ - .value.list = (struct sdp_def_data_element_s []) { val LAST }, \ - }, -#endif - -/* Try to keep each single attribute below MAX_PDU_OUT_SIZE bytes - * in resulting SDP data representation size. */ - -SERVICE(hid, - ATTRIBUTE(RECORD_HANDLE, UINT32(0)) /* Filled in later */ - ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(HID_SVCLASS_ID))) - ATTRIBUTE(RECORD_STATE, UINT32(1)) - ATTRIBUTE(PROTO_DESC_LIST, LIST( - LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_HID_CTRL)) - LIST(UUID128(HIDP_UUID)) - )) - ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002))) - ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST( - UINT16(0x656e) UINT16(0x006a) UINT16(0x0100) - )) - ATTRIBUTE(PFILE_DESC_LIST, LIST( - LIST(UUID128(HID_PROFILE_ID) UINT16(0x0100)) - )) - ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html")) - ATTRIBUTE(SVCNAME_PRIMARY, STRING("QEMU Bluetooth HID")) - ATTRIBUTE(SVCDESC_PRIMARY, STRING("QEMU Keyboard/Mouse")) - ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU")) - - /* Profile specific */ - ATTRIBUTE(DEVICE_RELEASE_NUMBER, UINT16(0x0091)) /* Deprecated, remove */ - ATTRIBUTE(PARSER_VERSION, UINT16(0x0111)) - /* TODO: extract from l2cap_device->device.class[0] */ - ATTRIBUTE(DEVICE_SUBCLASS, UINT8(0x40)) - ATTRIBUTE(COUNTRY_CODE, UINT8(0x15)) - ATTRIBUTE(VIRTUAL_CABLE, SDP_TRUE) - ATTRIBUTE(RECONNECT_INITIATE, SDP_FALSE) - /* TODO: extract from hid->usbdev->report_desc */ - ATTRIBUTE(DESCRIPTOR_LIST, LIST( - LIST(UINT8(0x22) ARRAY( - 0x05, 0x01, /* Usage Page (Generic Desktop) */ - 0x09, 0x06, /* Usage (Keyboard) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x75, 0x01, /* Report Size (1) */ - 0x95, 0x08, /* Report Count (8) */ - 0x05, 0x07, /* Usage Page (Key Codes) */ - 0x19, 0xe0, /* Usage Minimum (224) */ - 0x29, 0xe7, /* Usage Maximum (231) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x81, 0x02, /* Input (Data, Variable, Absolute) */ - 0x95, 0x01, /* Report Count (1) */ - 0x75, 0x08, /* Report Size (8) */ - 0x81, 0x01, /* Input (Constant) */ - 0x95, 0x05, /* Report Count (5) */ - 0x75, 0x01, /* Report Size (1) */ - 0x05, 0x08, /* Usage Page (LEDs) */ - 0x19, 0x01, /* Usage Minimum (1) */ - 0x29, 0x05, /* Usage Maximum (5) */ - 0x91, 0x02, /* Output (Data, Variable, Absolute) */ - 0x95, 0x01, /* Report Count (1) */ - 0x75, 0x03, /* Report Size (3) */ - 0x91, 0x01, /* Output (Constant) */ - 0x95, 0x06, /* Report Count (6) */ - 0x75, 0x08, /* Report Size (8) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0xff, /* Logical Maximum (255) */ - 0x05, 0x07, /* Usage Page (Key Codes) */ - 0x19, 0x00, /* Usage Minimum (0) */ - 0x29, 0xff, /* Usage Maximum (255) */ - 0x81, 0x00, /* Input (Data, Array) */ - 0xc0 /* End Collection */ - )))) - ATTRIBUTE(LANG_ID_BASE_LIST, LIST( - LIST(UINT16(0x0409) UINT16(0x0100)) - )) - ATTRIBUTE(SDP_DISABLE, SDP_FALSE) - ATTRIBUTE(BATTERY_POWER, SDP_TRUE) - ATTRIBUTE(REMOTE_WAKEUP, SDP_TRUE) - ATTRIBUTE(BOOT_DEVICE, SDP_TRUE) /* XXX: untested */ - ATTRIBUTE(SUPERVISION_TIMEOUT, UINT16(0x0c80)) - ATTRIBUTE(NORMALLY_CONNECTABLE, SDP_TRUE) - ATTRIBUTE(PROFILE_VERSION, UINT16(0x0100)) -) - -SERVICE(sdp, - ATTRIBUTE(RECORD_HANDLE, UINT32(0)) /* Filled in later */ - ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(SDP_SERVER_SVCLASS_ID))) - ATTRIBUTE(RECORD_STATE, UINT32(1)) - ATTRIBUTE(PROTO_DESC_LIST, LIST( - LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP)) - LIST(UUID128(SDP_UUID)) - )) - ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002))) - ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST( - UINT16(0x656e) UINT16(0x006a) UINT16(0x0100) - )) - ATTRIBUTE(PFILE_DESC_LIST, LIST( - LIST(UUID128(SDP_SERVER_PROFILE_ID) UINT16(0x0100)) - )) - ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html")) - ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU")) - - /* Profile specific */ - ATTRIBUTE(VERSION_NUM_LIST, LIST(UINT16(0x0100))) - ATTRIBUTE(SVCDB_STATE , UINT32(1)) -) - -SERVICE(pnp, - ATTRIBUTE(RECORD_HANDLE, UINT32(0)) /* Filled in later */ - ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(PNP_INFO_SVCLASS_ID))) - ATTRIBUTE(RECORD_STATE, UINT32(1)) - ATTRIBUTE(PROTO_DESC_LIST, LIST( - LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP)) - LIST(UUID128(SDP_UUID)) - )) - ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002))) - ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST( - UINT16(0x656e) UINT16(0x006a) UINT16(0x0100) - )) - ATTRIBUTE(PFILE_DESC_LIST, LIST( - LIST(UUID128(PNP_INFO_PROFILE_ID) UINT16(0x0100)) - )) - ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html")) - ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU")) - - /* Profile specific */ - ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100)) - ATTRIBUTE(VERSION, UINT16(0x0100)) - ATTRIBUTE(PRIMARY_RECORD, SDP_TRUE) -) - -static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev, - struct bt_l2cap_conn_params_s *params) -{ - struct bt_l2cap_sdp_state_s *sdp = g_malloc0(sizeof(*sdp)); - struct sdp_def_service_s *services[] = { - &sdp_service_sdp_s, - &sdp_service_hid_s, - &sdp_service_pnp_s, - NULL, - }; - - sdp->channel = params; - sdp->channel->opaque = sdp; - sdp->channel->close = bt_l2cap_sdp_close_ch; - sdp->channel->sdu_in = bt_l2cap_sdp_sdu_in; - - sdp_service_db_build(sdp, services); - - return 0; -} - -void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev) -{ - bt_l2cap_psm_register(dev, BT_PSM_SDP, - MAX_PDU_OUT_SIZE, bt_l2cap_sdp_new_ch); -} diff --git a/include/hw/bt.h b/include/hw/bt.h deleted file mode 100644 index d9ee2fc29a..0000000000 --- a/include/hw/bt.h +++ /dev/null @@ -1,2177 +0,0 @@ -/* - * QEMU Bluetooth HCI helpers. - * - * Copyright (C) 2007 OpenMoko, Inc. - * Written by Andrzej Zaborowski <andrew@openedhand.com> - * - * Useful definitions taken from BlueZ project's headers. - * Copyright (C) 2000-2001 Qualcomm Incorporated - * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> - * Copyright (C) 2002-2006 Marcel Holtmann <marcel@holtmann.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef HW_BT_H -#define HW_BT_H - - -/* BD Address */ -typedef struct { - uint8_t b[6]; -} QEMU_PACKED bdaddr_t; - -#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) -#define BDADDR_ALL (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}) -#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) - -/* Copy, swap, convert BD Address */ -static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2) -{ - return memcmp(ba1, ba2, sizeof(bdaddr_t)); -} -static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src) -{ - memcpy(dst, src, sizeof(bdaddr_t)); -} - -#define BAINIT(orig) { .b = { \ - (orig)->b[0], (orig)->b[1], (orig)->b[2], \ - (orig)->b[3], (orig)->b[4], (orig)->b[5], \ -}, } - -/* The twisted structures of a bluetooth environment */ -struct bt_device_s; -struct bt_scatternet_s; -struct bt_piconet_s; -struct bt_link_s; - -struct bt_scatternet_s { - struct bt_device_s *slave; -}; - -struct bt_link_s { - struct bt_device_s *slave, *host; - uint16_t handle; /* Master (host) side handle */ - uint16_t acl_interval; - enum { - acl_active, - acl_hold, - acl_sniff, - acl_parked, - } acl_mode; -}; - -struct bt_device_s { - int lt_addr; - bdaddr_t bd_addr; - int mtu; - int setup; - struct bt_scatternet_s *net; - - uint8_t key[16]; - int key_present; - uint8_t class[3]; - - uint8_t reject_reason; - - uint64_t lmp_caps; - const char *lmp_name; - void (*lmp_connection_request)(struct bt_link_s *link); - void (*lmp_connection_complete)(struct bt_link_s *link); - void (*lmp_disconnect_master)(struct bt_link_s *link); - void (*lmp_disconnect_slave)(struct bt_link_s *link); - void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data, - int start, int len); - void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data, - int start, int len); - void (*lmp_mode_change)(struct bt_link_s *link); - - void (*handle_destroy)(struct bt_device_s *device); - struct bt_device_s *next; /* Next in the piconet/scatternet */ - - int inquiry_scan; - int page_scan; - - uint16_t clkoff; /* Note: Always little-endian */ -}; - -extern struct HCIInfo null_hci; -/* bt.c */ -void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net); -void bt_device_done(struct bt_device_s *dev); -struct bt_scatternet_s *qemu_find_bt_vlan(int id); - -/* bt-hci.c */ -struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net); -struct HCIInfo *hci_init(const char *str); - -/* bt-vhci.c */ -void bt_vhci_init(struct HCIInfo *info); - -/* bt-hci-csr.c */ -enum { - csrhci_pin_reset, - csrhci_pin_wakeup, - __csrhci_pins, -}; -qemu_irq *csrhci_pins_get(Chardev *chr); -Chardev *uart_hci_init(void); - -/* bt-l2cap.c */ -struct bt_l2cap_device_s; -struct bt_l2cap_conn_params_s; -struct bt_l2cap_psm_s; -void bt_l2cap_device_init(struct bt_l2cap_device_s *dev, - struct bt_scatternet_s *net); -void bt_l2cap_device_done(struct bt_l2cap_device_s *dev); -void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm, - int min_mtu, int (*new_channel)(struct bt_l2cap_device_s *dev, - struct bt_l2cap_conn_params_s *params)); - -struct bt_l2cap_device_s { - struct bt_device_s device; - struct bt_l2cap_psm_s *first_psm; -}; - -struct bt_l2cap_conn_params_s { - /* Input */ - uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, int len); - void (*sdu_submit)(struct bt_l2cap_conn_params_s *chan); - int remote_mtu; - /* Output */ - void *opaque; - void (*sdu_in)(void *opaque, const uint8_t *data, int len); - void (*close)(void *opaque); -}; - -enum bt_l2cap_psm_predef { - BT_PSM_SDP = 0x0001, - BT_PSM_RFCOMM = 0x0003, - BT_PSM_TELEPHONY = 0x0005, - BT_PSM_TCS = 0x0007, - BT_PSM_BNEP = 0x000f, - BT_PSM_HID_CTRL = 0x0011, - BT_PSM_HID_INTR = 0x0013, - BT_PSM_UPNP = 0x0015, - BT_PSM_AVCTP = 0x0017, - BT_PSM_AVDTP = 0x0019, -}; - -/* bt-sdp.c */ -void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev); - -/* bt-hid.c */ -struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net); - -/* Link Management Protocol layer defines */ - -#define LLID_ACLU_CONT 0x1 -#define LLID_ACLU_START 0x2 -#define LLID_ACLC 0x3 - -enum lmp_pdu_type { - LMP_NAME_REQ = 0x0001, - LMP_NAME_RES = 0x0002, - LMP_ACCEPTED = 0x0003, - LMP_NOT_ACCEPTED = 0x0004, - LMP_CLKOFFSET_REQ = 0x0005, - LMP_CLKOFFSET_RES = 0x0006, - LMP_DETACH = 0x0007, - LMP_IN_RAND = 0x0008, - LMP_COMB_KEY = 0x0009, - LMP_UNIT_KEY = 0x000a, - LMP_AU_RAND = 0x000b, - LMP_SRES = 0x000c, - LMP_TEMP_RAND = 0x000d, - LMP_TEMP_KEY = 0x000e, - LMP_CRYPT_MODE_REQ = 0x000f, - LMP_CRYPT_KEY_SIZE_REQ = 0x0010, - LMP_START_ENCRYPT_REQ = 0x0011, - LMP_STOP_ENCRYPT_REQ = 0x0012, - LMP_SWITCH_REQ = 0x0013, - LMP_HOLD = 0x0014, - LMP_HOLD_REQ = 0x0015, - LMP_SNIFF_REQ = 0x0017, - LMP_UNSNIFF_REQ = 0x0018, - LMP_LMP_PARK_REQ = 0x0019, - LMP_SET_BCAST_SCAN_WND = 0x001b, - LMP_MODIFY_BEACON = 0x001c, - LMP_UNPARK_BD_ADDR_REQ = 0x001d, - LMP_UNPARK_PM_ADDR_REQ = 0x001e, - LMP_INCR_POWER_REQ = 0x001f, - LMP_DECR_POWER_REQ = 0x0020, - LMP_MAX_POWER = 0x0021, - LMP_MIN_POWER = 0x0022, - LMP_AUTO_RATE = 0x0023, - LMP_PREFERRED_RATE = 0x0024, - LMP_VERSION_REQ = 0x0025, - LMP_VERSION_RES = 0x0026, - LMP_FEATURES_REQ = 0x0027, - LMP_FEATURES_RES = 0x0028, - LMP_QUALITY_OF_SERVICE = 0x0029, - LMP_QOS_REQ = 0x002a, - LMP_RM_SCO_LINK_REQ = 0x002b, - LMP_SCO_LINK_REQ = 0x002c, - LMP_MAX_SLOT = 0x002d, - LMP_MAX_SLOT_REQ = 0x002e, - LMP_TIMING_ACCURACY_REQ = 0x002f, - LMP_TIMING_ACCURACY_RES = 0x0030, - LMP_SETUP_COMPLETE = 0x0031, - LMP_USE_SEMIPERM_KEY = 0x0032, - LMP_HOST_CONNECTION_REQ = 0x0033, - LMP_SLOT_OFFSET = 0x0034, - LMP_PAGE_MODE_REQ = 0x0035, - LMP_PAGE_SCAN_MODE_REQ = 0x0036, - LMP_SUPERVISION_TIMEOUT = 0x0037, - LMP_TEST_ACTIVATE = 0x0038, - LMP_TEST_CONTROL = 0x0039, - LMP_CRYPT_KEY_MASK_REQ = 0x003a, - LMP_CRYPT_KEY_MASK_RES = 0x003b, - LMP_SET_AFH = 0x003c, - LMP_ACCEPTED_EXT = 0x7f01, - LMP_NOT_ACCEPTED_EXT = 0x7f02, - LMP_FEATURES_REQ_EXT = 0x7f03, - LMP_FEATURES_RES_EXT = 0x7f04, - LMP_PACKET_TYPE_TBL_REQ = 0x7f0b, - LMP_ESCO_LINK_REQ = 0x7f0c, - LMP_RM_ESCO_LINK_REQ = 0x7f0d, - LMP_CHANNEL_CLASS_REQ = 0x7f10, - LMP_CHANNEL_CLASS = 0x7f11, -}; - -/* Host Controller Interface layer defines */ - -enum hci_packet_type { - HCI_COMMAND_PKT = 0x01, - HCI_ACLDATA_PKT = 0x02, - HCI_SCODATA_PKT = 0x03, - HCI_EVENT_PKT = 0x04, - HCI_VENDOR_PKT = 0xff, -}; - -enum bt_packet_type { - HCI_2DH1 = 1 << 1, - HCI_3DH1 = 1 << 2, - HCI_DM1 = 1 << 3, - HCI_DH1 = 1 << 4, - HCI_2DH3 = 1 << 8, - HCI_3DH3 = 1 << 9, - HCI_DM3 = 1 << 10, - HCI_DH3 = 1 << 11, - HCI_2DH5 = 1 << 12, - HCI_3DH5 = 1 << 13, - HCI_DM5 = 1 << 14, - HCI_DH5 = 1 << 15, -}; - -enum sco_packet_type { - HCI_HV1 = 1 << 5, - HCI_HV2 = 1 << 6, - HCI_HV3 = 1 << 7, -}; - -enum ev_packet_type { - HCI_EV3 = 1 << 3, - HCI_EV4 = 1 << 4, - HCI_EV5 = 1 << 5, - HCI_2EV3 = 1 << 6, - HCI_3EV3 = 1 << 7, - HCI_2EV5 = 1 << 8, - HCI_3EV5 = 1 << 9, -}; - -enum hci_error_code { - HCI_SUCCESS = 0x00, - HCI_UNKNOWN_COMMAND = 0x01, - HCI_NO_CONNECTION = 0x02, - HCI_HARDWARE_FAILURE = 0x03, - HCI_PAGE_TIMEOUT = 0x04, - HCI_AUTHENTICATION_FAILURE = 0x05, - HCI_PIN_OR_KEY_MISSING = 0x06, - HCI_MEMORY_FULL = 0x07, - HCI_CONNECTION_TIMEOUT = 0x08, - HCI_MAX_NUMBER_OF_CONNECTIONS = 0x09, - HCI_MAX_NUMBER_OF_SCO_CONNECTIONS = 0x0a, - HCI_ACL_CONNECTION_EXISTS = 0x0b, - HCI_COMMAND_DISALLOWED = 0x0c, - HCI_REJECTED_LIMITED_RESOURCES = 0x0d, - HCI_REJECTED_SECURITY = 0x0e, - HCI_REJECTED_PERSONAL = 0x0f, - HCI_HOST_TIMEOUT = 0x10, - HCI_UNSUPPORTED_FEATURE = 0x11, - HCI_INVALID_PARAMETERS = 0x12, - HCI_OE_USER_ENDED_CONNECTION = 0x13, - HCI_OE_LOW_RESOURCES = 0x14, - HCI_OE_POWER_OFF = 0x15, - HCI_CONNECTION_TERMINATED = 0x16, - HCI_REPEATED_ATTEMPTS = 0x17, - HCI_PAIRING_NOT_ALLOWED = 0x18, - HCI_UNKNOWN_LMP_PDU = 0x19, - HCI_UNSUPPORTED_REMOTE_FEATURE = 0x1a, - HCI_SCO_OFFSET_REJECTED = 0x1b, - HCI_SCO_INTERVAL_REJECTED = 0x1c, - HCI_AIR_MODE_REJECTED = 0x1d, - HCI_INVALID_LMP_PARAMETERS = 0x1e, - HCI_UNSPECIFIED_ERROR = 0x1f, - HCI_UNSUPPORTED_LMP_PARAMETER_VALUE = 0x20, - HCI_ROLE_CHANGE_NOT_ALLOWED = 0x21, - HCI_LMP_RESPONSE_TIMEOUT = 0x22, - HCI_LMP_ERROR_TRANSACTION_COLLISION = 0x23, - HCI_LMP_PDU_NOT_ALLOWED = 0x24, - HCI_ENCRYPTION_MODE_NOT_ACCEPTED = 0x25, - HCI_UNIT_LINK_KEY_USED = 0x26, - HCI_QOS_NOT_SUPPORTED = 0x27, - HCI_INSTANT_PASSED = 0x28, - HCI_PAIRING_NOT_SUPPORTED = 0x29, - HCI_TRANSACTION_COLLISION = 0x2a, - HCI_QOS_UNACCEPTABLE_PARAMETER = 0x2c, - HCI_QOS_REJECTED = 0x2d, - HCI_CLASSIFICATION_NOT_SUPPORTED = 0x2e, - HCI_INSUFFICIENT_SECURITY = 0x2f, - HCI_PARAMETER_OUT_OF_RANGE = 0x30, - HCI_ROLE_SWITCH_PENDING = 0x32, - HCI_SLOT_VIOLATION = 0x34, - HCI_ROLE_SWITCH_FAILED = 0x35, -}; - -enum acl_flag_bits { - ACL_CONT = 1 << 0, - ACL_START = 1 << 1, - ACL_ACTIVE_BCAST = 1 << 2, - ACL_PICO_BCAST = 1 << 3, -}; - -enum baseband_link_type { - SCO_LINK = 0x00, - ACL_LINK = 0x01, -}; - -enum lmp_feature_bits0 { - LMP_3SLOT = 1 << 0, - LMP_5SLOT = 1 << 1, - LMP_ENCRYPT = 1 << 2, - LMP_SOFFSET = 1 << 3, - LMP_TACCURACY = 1 << 4, - LMP_RSWITCH = 1 << 5, - LMP_HOLD_MODE = 1 << 6, - LMP_SNIFF_MODE = 1 << 7, -}; - -enum lmp_feature_bits1 { - LMP_PARK = 1 << 0, - LMP_RSSI = 1 << 1, - LMP_QUALITY = 1 << 2, - LMP_SCO = 1 << 3, - LMP_HV2 = 1 << 4, - LMP_HV3 = 1 << 5, - LMP_ULAW = 1 << 6, - LMP_ALAW = 1 << 7, -}; - -enum lmp_feature_bits2 { - LMP_CVSD = 1 << 0, - LMP_PSCHEME = 1 << 1, - LMP_PCONTROL = 1 << 2, - LMP_TRSP_SCO = 1 << 3, - LMP_BCAST_ENC = 1 << 7, -}; - -enum lmp_feature_bits3 { - LMP_EDR_ACL_2M = 1 << 1, - LMP_EDR_ACL_3M = 1 << 2, - LMP_ENH_ISCAN = 1 << 3, - LMP_ILACE_ISCAN = 1 << 4, - LMP_ILACE_PSCAN = 1 << 5, - LMP_RSSI_INQ = 1 << 6, - LMP_ESCO = 1 << 7, -}; - -enum lmp_feature_bits4 { - LMP_EV4 = 1 << 0, - LMP_EV5 = 1 << 1, - LMP_AFH_CAP_SLV = 1 << 3, - LMP_AFH_CLS_SLV = 1 << 4, - LMP_EDR_3SLOT = 1 << 7, -}; - -enum lmp_feature_bits5 { - LMP_EDR_5SLOT = 1 << 0, - LMP_SNIFF_SUBR = 1 << 1, - LMP_AFH_CAP_MST = 1 << 3, - LMP_AFH_CLS_MST = 1 << 4, - LMP_EDR_ESCO_2M = 1 << 5, - LMP_EDR_ESCO_3M = 1 << 6, - LMP_EDR_3S_ESCO = 1 << 7, -}; - -enum lmp_feature_bits6 { - LMP_EXT_INQ = 1 << 0, -}; - -enum lmp_feature_bits7 { - LMP_EXT_FEAT = 1 << 7, -}; - -enum hci_link_policy { - HCI_LP_RSWITCH = 1 << 0, - HCI_LP_HOLD = 1 << 1, - HCI_LP_SNIFF = 1 << 2, - HCI_LP_PARK = 1 << 3, -}; - -enum hci_link_mode { - HCI_LM_ACCEPT = 1 << 15, - HCI_LM_MASTER = 1 << 0, - HCI_LM_AUTH = 1 << 1, - HCI_LM_ENCRYPT = 1 << 2, - HCI_LM_TRUSTED = 1 << 3, - HCI_LM_RELIABLE = 1 << 4, - HCI_LM_SECURE = 1 << 5, -}; - -/* HCI Commands */ - -/* Link Control */ -#define OGF_LINK_CTL 0x01 - -#define OCF_INQUIRY 0x0001 -typedef struct { - uint8_t lap[3]; - uint8_t length; /* 1.28s units */ - uint8_t num_rsp; -} QEMU_PACKED inquiry_cp; -#define INQUIRY_CP_SIZE 5 - -typedef struct { - uint8_t status; - bdaddr_t bdaddr; -} QEMU_PACKED status_bdaddr_rp; -#define STATUS_BDADDR_RP_SIZE 7 - -#define OCF_INQUIRY_CANCEL 0x0002 - -#define OCF_PERIODIC_INQUIRY 0x0003 -typedef struct { - uint16_t max_period; /* 1.28s units */ - uint16_t min_period; /* 1.28s units */ - uint8_t lap[3]; - uint8_t length; /* 1.28s units */ - uint8_t num_rsp; -} QEMU_PACKED periodic_inquiry_cp; -#define PERIODIC_INQUIRY_CP_SIZE 9 - -#define OCF_EXIT_PERIODIC_INQUIRY 0x0004 - -#define OCF_CREATE_CONN 0x0005 -typedef struct { - bdaddr_t bdaddr; - uint16_t pkt_type; - uint8_t pscan_rep_mode; - uint8_t pscan_mode; - uint16_t clock_offset; - uint8_t role_switch; -} QEMU_PACKED create_conn_cp; -#define CREATE_CONN_CP_SIZE 13 - -#define OCF_DISCONNECT 0x0006 -typedef struct { - uint16_t handle; - uint8_t reason; -} QEMU_PACKED disconnect_cp; -#define DISCONNECT_CP_SIZE 3 - -#define OCF_ADD_SCO 0x0007 -typedef struct { - uint16_t handle; - uint16_t pkt_type; -} QEMU_PACKED add_sco_cp; -#define ADD_SCO_CP_SIZE 4 - -#define OCF_CREATE_CONN_CANCEL 0x0008 -typedef struct { - bdaddr_t bdaddr; -} QEMU_PACKED create_conn_cancel_cp; -#define CREATE_CONN_CANCEL_CP_SIZE 6 - -typedef struct { - uint8_t status; - bdaddr_t bdaddr; -} QEMU_PACKED create_conn_cancel_rp; -#define CREATE_CONN_CANCEL_RP_SIZE 7 - -#define OCF_ACCEPT_CONN_REQ 0x0009 -typedef struct { - bdaddr_t bdaddr; - uint8_t role; -} QEMU_PACKED accept_conn_req_cp; -#define ACCEPT_CONN_REQ_CP_SIZE 7 - -#define OCF_REJECT_CONN_REQ 0x000A -typedef struct { - bdaddr_t bdaddr; - uint8_t reason; -} QEMU_PACKED reject_conn_req_cp; -#define REJECT_CONN_REQ_CP_SIZE 7 - -#define OCF_LINK_KEY_REPLY 0x000B -typedef struct { - bdaddr_t bdaddr; - uint8_t link_key[16]; -} QEMU_PACKED link_key_reply_cp; -#define LINK_KEY_REPLY_CP_SIZE 22 - -#define OCF_LINK_KEY_NEG_REPLY 0x000C - -#define OCF_PIN_CODE_REPLY 0x000D -typedef struct { - bdaddr_t bdaddr; - uint8_t pin_len; - uint8_t pin_code[16]; -} QEMU_PACKED pin_code_reply_cp; -#define PIN_CODE_REPLY_CP_SIZE 23 - -#define OCF_PIN_CODE_NEG_REPLY 0x000E - -#define OCF_SET_CONN_PTYPE 0x000F -typedef struct { - uint16_t handle; - uint16_t pkt_type; -} QEMU_PACKED set_conn_ptype_cp; -#define SET_CONN_PTYPE_CP_SIZE 4 - -#define OCF_AUTH_REQUESTED 0x0011 -typedef struct { - uint16_t handle; -} QEMU_PACKED auth_requested_cp; -#define AUTH_REQUESTED_CP_SIZE 2 - -#define OCF_SET_CONN_ENCRYPT 0x0013 -typedef struct { - uint16_t handle; - uint8_t encrypt; -} QEMU_PACKED set_conn_encrypt_cp; -#define SET_CONN_ENCRYPT_CP_SIZE 3 - -#define OCF_CHANGE_CONN_LINK_KEY 0x0015 -typedef struct { - uint16_t handle; -} QEMU_PACKED change_conn_link_key_cp; -#define CHANGE_CONN_LINK_KEY_CP_SIZE 2 - -#define OCF_MASTER_LINK_KEY 0x0017 -typedef struct { - uint8_t key_flag; -} QEMU_PACKED master_link_key_cp; -#define MASTER_LINK_KEY_CP_SIZE 1 - -#define OCF_REMOTE_NAME_REQ 0x0019 -typedef struct { - bdaddr_t bdaddr; - uint8_t pscan_rep_mode; - uint8_t pscan_mode; - uint16_t clock_offset; -} QEMU_PACKED remote_name_req_cp; -#define REMOTE_NAME_REQ_CP_SIZE 10 - -#define OCF_REMOTE_NAME_REQ_CANCEL 0x001A -typedef struct { - bdaddr_t bdaddr; -} QEMU_PACKED remote_name_req_cancel_cp; -#define REMOTE_NAME_REQ_CANCEL_CP_SIZE 6 - -typedef struct { - uint8_t status; - bdaddr_t bdaddr; -} QEMU_PACKED remote_name_req_cancel_rp; -#define REMOTE_NAME_REQ_CANCEL_RP_SIZE 7 - -#define OCF_READ_REMOTE_FEATURES 0x001B -typedef struct { - uint16_t handle; -} QEMU_PACKED read_remote_features_cp; -#define READ_REMOTE_FEATURES_CP_SIZE 2 - -#define OCF_READ_REMOTE_EXT_FEATURES 0x001C -typedef struct { - uint16_t handle; - uint8_t page_num; -} QEMU_PACKED read_remote_ext_features_cp; -#define READ_REMOTE_EXT_FEATURES_CP_SIZE 3 - -#define OCF_READ_REMOTE_VERSION 0x001D -typedef struct { - uint16_t handle; -} QEMU_PACKED read_remote_version_cp; -#define READ_REMOTE_VERSION_CP_SIZE 2 - -#define OCF_READ_CLOCK_OFFSET 0x001F -typedef struct { - uint16_t handle; -} QEMU_PACKED read_clock_offset_cp; -#define READ_CLOCK_OFFSET_CP_SIZE 2 - -#define OCF_READ_LMP_HANDLE 0x0020 -typedef struct { - uint16_t handle; -} QEMU_PACKED read_lmp_handle_cp; -#define READ_LMP_HANDLE_CP_SIZE 2 - -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t lmp_handle; - uint32_t reserved; -} QEMU_PACKED read_lmp_handle_rp; -#define READ_LMP_HANDLE_RP_SIZE 8 - -#define OCF_SETUP_SYNC_CONN 0x0028 -typedef struct { - uint16_t handle; - uint32_t tx_bandwidth; - uint32_t rx_bandwidth; - uint16_t max_latency; - uint16_t voice_setting; - uint8_t retrans_effort; - uint16_t pkt_type; -} QEMU_PACKED setup_sync_conn_cp; -#define SETUP_SYNC_CONN_CP_SIZE 17 - -#define OCF_ACCEPT_SYNC_CONN_REQ 0x0029 -typedef struct { - bdaddr_t bdaddr; - uint32_t tx_bandwidth; - uint32_t rx_bandwidth; - uint16_t max_latency; - uint16_t voice_setting; - uint8_t retrans_effort; - uint16_t pkt_type; -} QEMU_PACKED accept_sync_conn_req_cp; -#define ACCEPT_SYNC_CONN_REQ_CP_SIZE 21 - -#define OCF_REJECT_SYNC_CONN_REQ 0x002A -typedef struct { - bdaddr_t bdaddr; - uint8_t reason; -} QEMU_PACKED reject_sync_conn_req_cp; -#define REJECT_SYNC_CONN_REQ_CP_SIZE 7 - -/* Link Policy */ -#define OGF_LINK_POLICY 0x02 - -#define OCF_HOLD_MODE 0x0001 -typedef struct { - uint16_t handle; - uint16_t max_interval; - uint16_t min_interval; -} QEMU_PACKED hold_mode_cp; -#define HOLD_MODE_CP_SIZE 6 - -#define OCF_SNIFF_MODE 0x0003 -typedef struct { - uint16_t handle; - uint16_t max_interval; - uint16_t min_interval; - uint16_t attempt; - uint16_t timeout; -} QEMU_PACKED sniff_mode_cp; -#define SNIFF_MODE_CP_SIZE 10 - -#define OCF_EXIT_SNIFF_MODE 0x0004 -typedef struct { - uint16_t handle; -} QEMU_PACKED exit_sniff_mode_cp; -#define EXIT_SNIFF_MODE_CP_SIZE 2 - -#define OCF_PARK_MODE 0x0005 -typedef struct { - uint16_t handle; - uint16_t max_interval; - uint16_t min_interval; -} QEMU_PACKED park_mode_cp; -#define PARK_MODE_CP_SIZE 6 - -#define OCF_EXIT_PARK_MODE 0x0006 -typedef struct { - uint16_t handle; -} QEMU_PACKED exit_park_mode_cp; -#define EXIT_PARK_MODE_CP_SIZE 2 - -#define OCF_QOS_SETUP 0x0007 -typedef struct { - uint8_t service_type; /* 1 = best effort */ - uint32_t token_rate; /* Byte per seconds */ - uint32_t peak_bandwidth; /* Byte per seconds */ - uint32_t latency; /* Microseconds */ - uint32_t delay_variation; /* Microseconds */ -} QEMU_PACKED hci_qos; -#define HCI_QOS_CP_SIZE 17 -typedef struct { - uint16_t handle; - uint8_t flags; /* Reserved */ - hci_qos qos; -} QEMU_PACKED qos_setup_cp; -#define QOS_SETUP_CP_SIZE (3 + HCI_QOS_CP_SIZE) - -#define OCF_ROLE_DISCOVERY 0x0009 -typedef struct { - uint16_t handle; -} QEMU_PACKED role_discovery_cp; -#define ROLE_DISCOVERY_CP_SIZE 2 -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t role; -} QEMU_PACKED role_discovery_rp; -#define ROLE_DISCOVERY_RP_SIZE 4 - -#define OCF_SWITCH_ROLE 0x000B -typedef struct { - bdaddr_t bdaddr; - uint8_t role; -} QEMU_PACKED switch_role_cp; -#define SWITCH_ROLE_CP_SIZE 7 - -#define OCF_READ_LINK_POLICY 0x000C -typedef struct { - uint16_t handle; -} QEMU_PACKED read_link_policy_cp; -#define READ_LINK_POLICY_CP_SIZE 2 -typedef struct { - uint8_t status; - uint16_t handle; - uint16_t policy; -} QEMU_PACKED read_link_policy_rp; -#define READ_LINK_POLICY_RP_SIZE 5 - -#define OCF_WRITE_LINK_POLICY 0x000D -typedef struct { - uint16_t handle; - uint16_t policy; -} QEMU_PACKED write_link_policy_cp; -#define WRITE_LINK_POLICY_CP_SIZE 4 -typedef struct { - uint8_t status; - uint16_t handle; -} QEMU_PACKED write_link_policy_rp; -#define WRITE_LINK_POLICY_RP_SIZE 3 - -#define OCF_READ_DEFAULT_LINK_POLICY 0x000E - -#define OCF_WRITE_DEFAULT_LINK_POLICY 0x000F - -#define OCF_FLOW_SPECIFICATION 0x0010 - -#define OCF_SNIFF_SUBRATE 0x0011 -typedef struct { - uint16_t handle; - uint16_t max_remote_latency; - uint16_t max_local_latency; - uint16_t min_remote_timeout; - uint16_t min_local_timeout; -} QEMU_PACKED sniff_subrate_cp; -#define SNIFF_SUBRATE_CP_SIZE 10 - -/* Host Controller and Baseband */ -#define OGF_HOST_CTL 0x03 - -#define OCF_SET_EVENT_MASK 0x0001 -typedef struct { - uint8_t mask[8]; -} QEMU_PACKED set_event_mask_cp; -#define SET_EVENT_MASK_CP_SIZE 8 - -#define OCF_RESET 0x0003 - -#define OCF_SET_EVENT_FLT 0x0005 -typedef struct { - uint8_t flt_type; - uint8_t cond_type; - uint8_t condition[0]; -} QEMU_PACKED set_event_flt_cp; -#define SET_EVENT_FLT_CP_SIZE 2 - -enum bt_filter_type { - FLT_CLEAR_ALL = 0x00, - FLT_INQ_RESULT = 0x01, - FLT_CONN_SETUP = 0x02, -}; -enum inq_result_cond_type { - INQ_RESULT_RETURN_ALL = 0x00, - INQ_RESULT_RETURN_CLASS = 0x01, - INQ_RESULT_RETURN_BDADDR = 0x02, -}; -enum conn_setup_cond_type { - CONN_SETUP_ALLOW_ALL = 0x00, - CONN_SETUP_ALLOW_CLASS = 0x01, - CONN_SETUP_ALLOW_BDADDR = 0x02, -}; -enum conn_setup_cond { - CONN_SETUP_AUTO_OFF = 0x01, - CONN_SETUP_AUTO_ON = 0x02, -}; - -#define OCF_FLUSH 0x0008 -typedef struct { - uint16_t handle; -} QEMU_PACKED flush_cp; -#define FLUSH_CP_SIZE 2 - -typedef struct { - uint8_t status; - uint16_t handle; -} QEMU_PACKED flush_rp; -#define FLUSH_RP_SIZE 3 - -#define OCF_READ_PIN_TYPE 0x0009 -typedef struct { - uint8_t status; - uint8_t pin_type; -} QEMU_PACKED read_pin_type_rp; -#define READ_PIN_TYPE_RP_SIZE 2 - -#define OCF_WRITE_PIN_TYPE 0x000A -typedef struct { - uint8_t pin_type; -} QEMU_PACKED write_pin_type_cp; -#define WRITE_PIN_TYPE_CP_SIZE 1 - -#define OCF_CREATE_NEW_UNIT_KEY 0x000B - -#define OCF_READ_STORED_LINK_KEY 0x000D -typedef struct { - bdaddr_t bdaddr; - uint8_t read_all; -} QEMU_PACKED read_stored_link_key_cp; -#define READ_STORED_LINK_KEY_CP_SIZE 7 -typedef struct { - uint8_t status; - uint16_t max_keys; - uint16_t num_keys; -} QEMU_PACKED read_stored_link_key_rp; -#define READ_STORED_LINK_KEY_RP_SIZE 5 - -#define OCF_WRITE_STORED_LINK_KEY 0x0011 -typedef struct { - uint8_t num_keys; - /* variable length part */ -} QEMU_PACKED write_stored_link_key_cp; -#define WRITE_STORED_LINK_KEY_CP_SIZE 1 -typedef struct { - uint8_t status; - uint8_t num_keys; -} QEMU_PACKED write_stored_link_key_rp; -#define READ_WRITE_LINK_KEY_RP_SIZE 2 - -#define OCF_DELETE_STORED_LINK_KEY 0x0012 -typedef struct { - bdaddr_t bdaddr; - uint8_t delete_all; -} QEMU_PACKED delete_stored_link_key_cp; -#define DELETE_STORED_LINK_KEY_CP_SIZE 7 -typedef struct { - uint8_t status; - uint16_t num_keys; -} QEMU_PACKED delete_stored_link_key_rp; -#define DELETE_STORED_LINK_KEY_RP_SIZE 3 - -#define OCF_CHANGE_LOCAL_NAME 0x0013 -typedef struct { - char name[248]; -} QEMU_PACKED change_local_name_cp; -#define CHANGE_LOCAL_NAME_CP_SIZE 248 - -#define OCF_READ_LOCAL_NAME 0x0014 -typedef struct { - uint8_t status; - char name[248]; -} QEMU_PACKED read_local_name_rp; -#define READ_LOCAL_NAME_RP_SIZE 249 - -#define OCF_READ_CONN_ACCEPT_TIMEOUT 0x0015 -typedef struct { - uint8_t status; - uint16_t timeout; -} QEMU_PACKED read_conn_accept_timeout_rp; -#define READ_CONN_ACCEPT_TIMEOUT_RP_SIZE 3 - -#define OCF_WRITE_CONN_ACCEPT_TIMEOUT 0x0016 -typedef struct { - uint16_t timeout; -} QEMU_PACKED write_conn_accept_timeout_cp; -#define WRITE_CONN_ACCEPT_TIMEOUT_CP_SIZE 2 - -#define OCF_READ_PAGE_TIMEOUT 0x0017 -typedef struct { - uint8_t status; - uint16_t timeout; -} QEMU_PACKED read_page_timeout_rp; -#define READ_PAGE_TIMEOUT_RP_SIZE 3 - -#define OCF_WRITE_PAGE_TIMEOUT 0x0018 -typedef struct { - uint16_t timeout; -} QEMU_PACKED write_page_timeout_cp; -#define WRITE_PAGE_TIMEOUT_CP_SIZE 2 - -#define OCF_READ_SCAN_ENABLE 0x0019 -typedef struct { - uint8_t status; - uint8_t enable; -} QEMU_PACKED read_scan_enable_rp; -#define READ_SCAN_ENABLE_RP_SIZE 2 - -#define OCF_WRITE_SCAN_ENABLE 0x001A -typedef struct { - uint8_t scan_enable; -} QEMU_PACKED write_scan_enable_cp; -#define WRITE_SCAN_ENABLE_CP_SIZE 1 - -enum scan_enable_bits { - SCAN_DISABLED = 0, - SCAN_INQUIRY = 1 << 0, - SCAN_PAGE = 1 << 1, -}; - -#define OCF_READ_PAGE_ACTIVITY 0x001B -typedef struct { - uint8_t status; - uint16_t interval; - uint16_t window; -} QEMU_PACKED read_page_activity_rp; -#define READ_PAGE_ACTIVITY_RP_SIZE 5 - -#define OCF_WRITE_PAGE_ACTIVITY 0x001C -typedef struct { - uint16_t interval; - uint16_t window; -} QEMU_PACKED write_page_activity_cp; -#define WRITE_PAGE_ACTIVITY_CP_SIZE 4 - -#define OCF_READ_INQ_ACTIVITY 0x001D -typedef struct { - uint8_t status; - uint16_t interval; - uint16_t window; -} QEMU_PACKED read_inq_activity_rp; -#define READ_INQ_ACTIVITY_RP_SIZE 5 - -#define OCF_WRITE_INQ_ACTIVITY 0x001E -typedef struct { - uint16_t interval; - uint16_t window; -} QEMU_PACKED write_inq_activity_cp; -#define WRITE_INQ_ACTIVITY_CP_SIZE 4 - -#define OCF_READ_AUTH_ENABLE 0x001F - -#define OCF_WRITE_AUTH_ENABLE 0x0020 - -#define AUTH_DISABLED 0x00 -#define AUTH_ENABLED 0x01 - -#define OCF_READ_ENCRYPT_MODE 0x0021 - -#define OCF_WRITE_ENCRYPT_MODE 0x0022 - -#define ENCRYPT_DISABLED 0x00 -#define ENCRYPT_P2P 0x01 -#define ENCRYPT_BOTH 0x02 - -#define OCF_READ_CLASS_OF_DEV 0x0023 -typedef struct { - uint8_t status; - uint8_t dev_class[3]; -} QEMU_PACKED read_class_of_dev_rp; -#define READ_CLASS_OF_DEV_RP_SIZE 4 - -#define OCF_WRITE_CLASS_OF_DEV 0x0024 -typedef struct { - uint8_t dev_class[3]; -} QEMU_PACKED write_class_of_dev_cp; -#define WRITE_CLASS_OF_DEV_CP_SIZE 3 - -#define OCF_READ_VOICE_SETTING 0x0025 -typedef struct { - uint8_t status; - uint16_t voice_setting; -} QEMU_PACKED read_voice_setting_rp; -#define READ_VOICE_SETTING_RP_SIZE 3 - -#define OCF_WRITE_VOICE_SETTING 0x0026 -typedef struct { - uint16_t voice_setting; -} QEMU_PACKED write_voice_setting_cp; -#define WRITE_VOICE_SETTING_CP_SIZE 2 - -#define OCF_READ_AUTOMATIC_FLUSH_TIMEOUT 0x0027 - -#define OCF_WRITE_AUTOMATIC_FLUSH_TIMEOUT 0x0028 - -#define OCF_READ_NUM_BROADCAST_RETRANS 0x0029 - -#define OCF_WRITE_NUM_BROADCAST_RETRANS 0x002A - -#define OCF_READ_HOLD_MODE_ACTIVITY 0x002B - -#define OCF_WRITE_HOLD_MODE_ACTIVITY 0x002C - -#define OCF_READ_TRANSMIT_POWER_LEVEL 0x002D -typedef struct { - uint16_t handle; - uint8_t type; -} QEMU_PACKED read_transmit_power_level_cp; -#define READ_TRANSMIT_POWER_LEVEL_CP_SIZE 3 -typedef struct { - uint8_t status; - uint16_t handle; - int8_t level; -} QEMU_PACKED read_transmit_power_level_rp; -#define READ_TRANSMIT_POWER_LEVEL_RP_SIZE 4 - -#define OCF_HOST_BUFFER_SIZE 0x0033 -typedef struct { - uint16_t acl_mtu; - uint8_t sco_mtu; - uint16_t acl_max_pkt; - uint16_t sco_max_pkt; -} QEMU_PACKED host_buffer_size_cp; -#define HOST_BUFFER_SIZE_CP_SIZE 7 - -#define OCF_HOST_NUMBER_OF_COMPLETED_PACKETS 0x0035 - -#define OCF_READ_LINK_SUPERVISION_TIMEOUT 0x0036 -typedef struct { - uint8_t status; - uint16_t handle; - uint16_t link_sup_to; -} QEMU_PACKED read_link_supervision_timeout_rp; -#define READ_LINK_SUPERVISION_TIMEOUT_RP_SIZE 5 - -#define OCF_WRITE_LINK_SUPERVISION_TIMEOUT 0x0037 -typedef struct { - uint16_t handle; - uint16_t link_sup_to; -} QEMU_PACKED write_link_supervision_timeout_cp; -#define WRITE_LINK_SUPERVISION_TIMEOUT_CP_SIZE 4 -typedef struct { - uint8_t status; - uint16_t handle; -} QEMU_PACKED write_link_supervision_timeout_rp; -#define WRITE_LINK_SUPERVISION_TIMEOUT_RP_SIZE 3 - -#define OCF_READ_NUM_SUPPORTED_IAC 0x0038 - -#define MAX_IAC_LAP 0x40 -#define OCF_READ_CURRENT_IAC_LAP 0x0039 -typedef struct { - uint8_t status; - uint8_t num_current_iac; - uint8_t lap[MAX_IAC_LAP][3]; -} QEMU_PACKED read_current_iac_lap_rp; -#define READ_CURRENT_IAC_LAP_RP_SIZE 2+3*MAX_IAC_LAP - -#define OCF_WRITE_CURRENT_IAC_LAP 0x003A -typedef struct { - uint8_t num_current_iac; - uint8_t lap[MAX_IAC_LAP][3]; -} QEMU_PACKED write_current_iac_lap_cp; -#define WRITE_CURRENT_IAC_LAP_CP_SIZE 1+3*MAX_IAC_LAP - -#define OCF_READ_PAGE_SCAN_PERIOD_MODE 0x003B - -#define OCF_WRITE_PAGE_SCAN_PERIOD_MODE 0x003C - -#define OCF_READ_PAGE_SCAN_MODE 0x003D - -#define OCF_WRITE_PAGE_SCAN_MODE 0x003E - -#define OCF_SET_AFH_CLASSIFICATION 0x003F -typedef struct { - uint8_t map[10]; -} QEMU_PACKED set_afh_classification_cp; -#define SET_AFH_CLASSIFICATION_CP_SIZE 10 -typedef struct { - uint8_t status; -} QEMU_PACKED set_afh_classification_rp; -#define SET_AFH_CLASSIFICATION_RP_SIZE 1 - -#define OCF_READ_INQUIRY_SCAN_TYPE 0x0042 -typedef struct { - uint8_t status; - uint8_t type; -} QEMU_PACKED read_inquiry_scan_type_rp; -#define READ_INQUIRY_SCAN_TYPE_RP_SIZE 2 - -#define OCF_WRITE_INQUIRY_SCAN_TYPE 0x0043 -typedef struct { - uint8_t type; -} QEMU_PACKED write_inquiry_scan_type_cp; -#define WRITE_INQUIRY_SCAN_TYPE_CP_SIZE 1 -typedef struct { - uint8_t status; -} QEMU_PACKED write_inquiry_scan_type_rp; -#define WRITE_INQUIRY_SCAN_TYPE_RP_SIZE 1 - -#define OCF_READ_INQUIRY_MODE 0x0044 -typedef struct { - uint8_t status; - uint8_t mode; -} QEMU_PACKED read_inquiry_mode_rp; -#define READ_INQUIRY_MODE_RP_SIZE 2 - -#define OCF_WRITE_INQUIRY_MODE 0x0045 -typedef struct { - uint8_t mode; -} QEMU_PACKED write_inquiry_mode_cp; -#define WRITE_INQUIRY_MODE_CP_SIZE 1 -typedef struct { - uint8_t status; -} QEMU_PACKED write_inquiry_mode_rp; -#define WRITE_INQUIRY_MODE_RP_SIZE 1 - -#define OCF_READ_PAGE_SCAN_TYPE 0x0046 - -#define OCF_WRITE_PAGE_SCAN_TYPE 0x0047 - -#define OCF_READ_AFH_MODE 0x0048 -typedef struct { - uint8_t status; - uint8_t mode; -} QEMU_PACKED read_afh_mode_rp; -#define READ_AFH_MODE_RP_SIZE 2 - -#define OCF_WRITE_AFH_MODE 0x0049 -typedef struct { - uint8_t mode; -} QEMU_PACKED write_afh_mode_cp; -#define WRITE_AFH_MODE_CP_SIZE 1 -typedef struct { - uint8_t status; -} QEMU_PACKED write_afh_mode_rp; -#define WRITE_AFH_MODE_RP_SIZE 1 - -#define OCF_READ_EXT_INQUIRY_RESPONSE 0x0051 -typedef struct { - uint8_t status; - uint8_t fec; - uint8_t data[240]; -} QEMU_PACKED read_ext_inquiry_response_rp; -#define READ_EXT_INQUIRY_RESPONSE_RP_SIZE 242 - -#define OCF_WRITE_EXT_INQUIRY_RESPONSE 0x0052 -typedef struct { - uint8_t fec; - uint8_t data[240]; -} QEMU_PACKED write_ext_inquiry_response_cp; -#define WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE 241 -typedef struct { - uint8_t status; -} QEMU_PACKED write_ext_inquiry_response_rp; -#define WRITE_EXT_INQUIRY_RESPONSE_RP_SIZE 1 - -/* Informational Parameters */ -#define OGF_INFO_PARAM 0x04 - -#define OCF_READ_LOCAL_VERSION 0x0001 -typedef struct { - uint8_t status; - uint8_t hci_ver; - uint16_t hci_rev; - uint8_t lmp_ver; - uint16_t manufacturer; - uint16_t lmp_subver; -} QEMU_PACKED read_local_version_rp; -#define READ_LOCAL_VERSION_RP_SIZE 9 - -#define OCF_READ_LOCAL_COMMANDS 0x0002 -typedef struct { - uint8_t status; - uint8_t commands[64]; -} QEMU_PACKED read_local_commands_rp; -#define READ_LOCAL_COMMANDS_RP_SIZE 65 - -#define OCF_READ_LOCAL_FEATURES 0x0003 -typedef struct { - uint8_t status; - uint8_t features[8]; -} QEMU_PACKED read_local_features_rp; -#define READ_LOCAL_FEATURES_RP_SIZE 9 - -#define OCF_READ_LOCAL_EXT_FEATURES 0x0004 -typedef struct { - uint8_t page_num; -} QEMU_PACKED read_local_ext_features_cp; -#define READ_LOCAL_EXT_FEATURES_CP_SIZE 1 -typedef struct { - uint8_t status; - uint8_t page_num; - uint8_t max_page_num; - uint8_t features[8]; -} QEMU_PACKED read_local_ext_features_rp; -#define READ_LOCAL_EXT_FEATURES_RP_SIZE 11 - -#define OCF_READ_BUFFER_SIZE 0x0005 -typedef struct { - uint8_t status; - uint16_t acl_mtu; - uint8_t sco_mtu; - uint16_t acl_max_pkt; - uint16_t sco_max_pkt; -} QEMU_PACKED read_buffer_size_rp; -#define READ_BUFFER_SIZE_RP_SIZE 8 - -#define OCF_READ_COUNTRY_CODE 0x0007 -typedef struct { - uint8_t status; - uint8_t country_code; -} QEMU_PACKED read_country_code_rp; -#define READ_COUNTRY_CODE_RP_SIZE 2 - -#define OCF_READ_BD_ADDR 0x0009 -typedef struct { - uint8_t status; - bdaddr_t bdaddr; -} QEMU_PACKED read_bd_addr_rp; -#define READ_BD_ADDR_RP_SIZE 7 - -/* Status params */ -#define OGF_STATUS_PARAM 0x05 - -#define OCF_READ_FAILED_CONTACT_COUNTER 0x0001 -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t counter; -} QEMU_PACKED read_failed_contact_counter_rp; -#define READ_FAILED_CONTACT_COUNTER_RP_SIZE 4 - -#define OCF_RESET_FAILED_CONTACT_COUNTER 0x0002 -typedef struct { - uint8_t status; - uint16_t handle; -} QEMU_PACKED reset_failed_contact_counter_rp; -#define RESET_FAILED_CONTACT_COUNTER_RP_SIZE 3 - -#define OCF_READ_LINK_QUALITY 0x0003 -typedef struct { - uint16_t handle; -} QEMU_PACKED read_link_quality_cp; -#define READ_LINK_QUALITY_CP_SIZE 2 - -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t link_quality; -} QEMU_PACKED read_link_quality_rp; -#define READ_LINK_QUALITY_RP_SIZE 4 - -#define OCF_READ_RSSI 0x0005 -typedef struct { - uint8_t status; - uint16_t handle; - int8_t rssi; -} QEMU_PACKED read_rssi_rp; -#define READ_RSSI_RP_SIZE 4 - -#define OCF_READ_AFH_MAP 0x0006 -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t mode; - uint8_t map[10]; -} QEMU_PACKED read_afh_map_rp; -#define READ_AFH_MAP_RP_SIZE 14 - -#define OCF_READ_CLOCK 0x0007 -typedef struct { - uint16_t handle; - uint8_t which_clock; -} QEMU_PACKED read_clock_cp; -#define READ_CLOCK_CP_SIZE 3 -typedef struct { - uint8_t status; - uint16_t handle; - uint32_t clock; - uint16_t accuracy; -} QEMU_PACKED read_clock_rp; -#define READ_CLOCK_RP_SIZE 9 - -/* Testing commands */ -#define OGF_TESTING_CMD 0x3e - -/* Vendor specific commands */ -#define OGF_VENDOR_CMD 0x3f - -/* HCI Events */ - -#define EVT_INQUIRY_COMPLETE 0x01 - -#define EVT_INQUIRY_RESULT 0x02 -typedef struct { - uint8_t num_responses; - bdaddr_t bdaddr; - uint8_t pscan_rep_mode; - uint8_t pscan_period_mode; - uint8_t pscan_mode; - uint8_t dev_class[3]; - uint16_t clock_offset; -} QEMU_PACKED inquiry_info; -#define INQUIRY_INFO_SIZE 15 - -#define EVT_CONN_COMPLETE 0x03 -typedef struct { - uint8_t status; - uint16_t handle; - bdaddr_t bdaddr; - uint8_t link_type; - uint8_t encr_mode; -} QEMU_PACKED evt_conn_complete; -#define EVT_CONN_COMPLETE_SIZE 11 - -#define EVT_CONN_REQUEST 0x04 -typedef struct { - bdaddr_t bdaddr; - uint8_t dev_class[3]; - uint8_t link_type; -} QEMU_PACKED evt_conn_request; -#define EVT_CONN_REQUEST_SIZE 10 - -#define EVT_DISCONN_COMPLETE 0x05 -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t reason; -} QEMU_PACKED evt_disconn_complete; -#define EVT_DISCONN_COMPLETE_SIZE 4 - -#define EVT_AUTH_COMPLETE 0x06 -typedef struct { - uint8_t status; - uint16_t handle; -} QEMU_PACKED evt_auth_complete; -#define EVT_AUTH_COMPLETE_SIZE 3 - -#define EVT_REMOTE_NAME_REQ_COMPLETE 0x07 -typedef struct { - uint8_t status; - bdaddr_t bdaddr; - char name[248]; -} QEMU_PACKED evt_remote_name_req_complete; -#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255 - -#define EVT_ENCRYPT_CHANGE 0x08 -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t encrypt; -} QEMU_PACKED evt_encrypt_change; -#define EVT_ENCRYPT_CHANGE_SIZE 4 - -#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE 0x09 -typedef struct { - uint8_t status; - uint16_t handle; -} QEMU_PACKED evt_change_conn_link_key_complete; -#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE_SIZE 3 - -#define EVT_MASTER_LINK_KEY_COMPLETE 0x0A -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t key_flag; -} QEMU_PACKED evt_master_link_key_complete; -#define EVT_MASTER_LINK_KEY_COMPLETE_SIZE 4 - -#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t features[8]; -} QEMU_PACKED evt_read_remote_features_complete; -#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11 - -#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t lmp_ver; - uint16_t manufacturer; - uint16_t lmp_subver; -} QEMU_PACKED evt_read_remote_version_complete; -#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8 - -#define EVT_QOS_SETUP_COMPLETE 0x0D -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t flags; /* Reserved */ - hci_qos qos; -} QEMU_PACKED evt_qos_setup_complete; -#define EVT_QOS_SETUP_COMPLETE_SIZE (4 + HCI_QOS_CP_SIZE) - -#define EVT_CMD_COMPLETE 0x0E -typedef struct { - uint8_t ncmd; - uint16_t opcode; -} QEMU_PACKED evt_cmd_complete; -#define EVT_CMD_COMPLETE_SIZE 3 - -#define EVT_CMD_STATUS 0x0F -typedef struct { - uint8_t status; - uint8_t ncmd; - uint16_t opcode; -} QEMU_PACKED evt_cmd_status; -#define EVT_CMD_STATUS_SIZE 4 - -#define EVT_HARDWARE_ERROR 0x10 -typedef struct { - uint8_t code; -} QEMU_PACKED evt_hardware_error; -#define EVT_HARDWARE_ERROR_SIZE 1 - -#define EVT_FLUSH_OCCURRED 0x11 -typedef struct { - uint16_t handle; -} QEMU_PACKED evt_flush_occurred; -#define EVT_FLUSH_OCCURRED_SIZE 2 - -#define EVT_ROLE_CHANGE 0x12 -typedef struct { - uint8_t status; - bdaddr_t bdaddr; - uint8_t role; -} QEMU_PACKED evt_role_change; -#define EVT_ROLE_CHANGE_SIZE 8 - -#define EVT_NUM_COMP_PKTS 0x13 -typedef struct { - uint8_t num_hndl; - struct { - uint16_t handle; - uint16_t num_packets; - } connection[0]; -} QEMU_PACKED evt_num_comp_pkts; -#define EVT_NUM_COMP_PKTS_SIZE(num_hndl) (1 + 4 * (num_hndl)) - -#define EVT_MODE_CHANGE 0x14 -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t mode; - uint16_t interval; -} QEMU_PACKED evt_mode_change; -#define EVT_MODE_CHANGE_SIZE 6 - -#define EVT_RETURN_LINK_KEYS 0x15 -typedef struct { - uint8_t num_keys; - /* variable length part */ -} QEMU_PACKED evt_return_link_keys; -#define EVT_RETURN_LINK_KEYS_SIZE 1 - -#define EVT_PIN_CODE_REQ 0x16 -typedef struct { - bdaddr_t bdaddr; -} QEMU_PACKED evt_pin_code_req; -#define EVT_PIN_CODE_REQ_SIZE 6 - -#define EVT_LINK_KEY_REQ 0x17 -typedef struct { - bdaddr_t bdaddr; -} QEMU_PACKED evt_link_key_req; -#define EVT_LINK_KEY_REQ_SIZE 6 - -#define EVT_LINK_KEY_NOTIFY 0x18 -typedef struct { - bdaddr_t bdaddr; - uint8_t link_key[16]; - uint8_t key_type; -} QEMU_PACKED evt_link_key_notify; -#define EVT_LINK_KEY_NOTIFY_SIZE 23 - -#define EVT_LOOPBACK_COMMAND 0x19 - -#define EVT_DATA_BUFFER_OVERFLOW 0x1A -typedef struct { - uint8_t link_type; -} QEMU_PACKED evt_data_buffer_overflow; -#define EVT_DATA_BUFFER_OVERFLOW_SIZE 1 - -#define EVT_MAX_SLOTS_CHANGE 0x1B -typedef struct { - uint16_t handle; - uint8_t max_slots; -} QEMU_PACKED evt_max_slots_change; -#define EVT_MAX_SLOTS_CHANGE_SIZE 3 - -#define EVT_READ_CLOCK_OFFSET_COMPLETE 0x1C -typedef struct { - uint8_t status; - uint16_t handle; - uint16_t clock_offset; -} QEMU_PACKED evt_read_clock_offset_complete; -#define EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE 5 - -#define EVT_CONN_PTYPE_CHANGED 0x1D -typedef struct { - uint8_t status; - uint16_t handle; - uint16_t ptype; -} QEMU_PACKED evt_conn_ptype_changed; -#define EVT_CONN_PTYPE_CHANGED_SIZE 5 - -#define EVT_QOS_VIOLATION 0x1E -typedef struct { - uint16_t handle; -} QEMU_PACKED evt_qos_violation; -#define EVT_QOS_VIOLATION_SIZE 2 - -#define EVT_PSCAN_REP_MODE_CHANGE 0x20 -typedef struct { - bdaddr_t bdaddr; - uint8_t pscan_rep_mode; -} QEMU_PACKED evt_pscan_rep_mode_change; -#define EVT_PSCAN_REP_MODE_CHANGE_SIZE 7 - -#define EVT_FLOW_SPEC_COMPLETE 0x21 -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t flags; - uint8_t direction; - hci_qos qos; -} QEMU_PACKED evt_flow_spec_complete; -#define EVT_FLOW_SPEC_COMPLETE_SIZE (5 + HCI_QOS_CP_SIZE) - -#define EVT_INQUIRY_RESULT_WITH_RSSI 0x22 -typedef struct { - uint8_t num_responses; - bdaddr_t bdaddr; - uint8_t pscan_rep_mode; - uint8_t pscan_period_mode; - uint8_t dev_class[3]; - uint16_t clock_offset; - int8_t rssi; -} QEMU_PACKED inquiry_info_with_rssi; -#define INQUIRY_INFO_WITH_RSSI_SIZE 15 -typedef struct { - uint8_t num_responses; - bdaddr_t bdaddr; - uint8_t pscan_rep_mode; - uint8_t pscan_period_mode; - uint8_t pscan_mode; - uint8_t dev_class[3]; - uint16_t clock_offset; - int8_t rssi; -} QEMU_PACKED inquiry_info_with_rssi_and_pscan_mode; -#define INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE 16 - -#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE 0x23 -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t page_num; - uint8_t max_page_num; - uint8_t features[8]; -} QEMU_PACKED evt_read_remote_ext_features_complete; -#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE 13 - -#define EVT_SYNC_CONN_COMPLETE 0x2C -typedef struct { - uint8_t status; - uint16_t handle; - bdaddr_t bdaddr; - uint8_t link_type; - uint8_t trans_interval; - uint8_t retrans_window; - uint16_t rx_pkt_len; - uint16_t tx_pkt_len; - uint8_t air_mode; -} QEMU_PACKED evt_sync_conn_complete; -#define EVT_SYNC_CONN_COMPLETE_SIZE 17 - -#define EVT_SYNC_CONN_CHANGED 0x2D -typedef struct { - uint8_t status; - uint16_t handle; - uint8_t trans_interval; - uint8_t retrans_window; - uint16_t rx_pkt_len; - uint16_t tx_pkt_len; -} QEMU_PACKED evt_sync_conn_changed; -#define EVT_SYNC_CONN_CHANGED_SIZE 9 - -#define EVT_SNIFF_SUBRATE 0x2E -typedef struct { - uint8_t status; - uint16_t handle; - uint16_t max_remote_latency; - uint16_t max_local_latency; - uint16_t min_remote_timeout; - uint16_t min_local_timeout; -} QEMU_PACKED evt_sniff_subrate; -#define EVT_SNIFF_SUBRATE_SIZE 11 - -#define EVT_TESTING 0xFE - -#define EVT_VENDOR 0xFF - -/* Command opcode pack/unpack */ -#define cmd_opcode_pack(ogf, ocf) (uint16_t)((ocf & 0x03ff)|(ogf << 10)) -#define cmd_opcode_ogf(op) (op >> 10) -#define cmd_opcode_ocf(op) (op & 0x03ff) - -/* ACL handle and flags pack/unpack */ -#define acl_handle_pack(h, f) (uint16_t)(((h) & 0x0fff)|((f) << 12)) -#define acl_handle(h) ((h) & 0x0fff) -#define acl_flags(h) ((h) >> 12) - -/* HCI Packet structures */ -#define HCI_COMMAND_HDR_SIZE 3 -#define HCI_EVENT_HDR_SIZE 2 -#define HCI_ACL_HDR_SIZE 4 -#define HCI_SCO_HDR_SIZE 3 - -struct hci_command_hdr { - uint16_t opcode; /* OCF & OGF */ - uint8_t plen; -} QEMU_PACKED; - -struct hci_event_hdr { - uint8_t evt; - uint8_t plen; -} QEMU_PACKED; - -struct hci_acl_hdr { - uint16_t handle; /* Handle & Flags(PB, BC) */ - uint16_t dlen; -} QEMU_PACKED; - -struct hci_sco_hdr { - uint16_t handle; - uint8_t dlen; -} QEMU_PACKED; - -/* L2CAP layer defines */ - -enum bt_l2cap_lm_bits { - L2CAP_LM_MASTER = 1 << 0, - L2CAP_LM_AUTH = 1 << 1, - L2CAP_LM_ENCRYPT = 1 << 2, - L2CAP_LM_TRUSTED = 1 << 3, - L2CAP_LM_RELIABLE = 1 << 4, - L2CAP_LM_SECURE = 1 << 5, -}; - -enum bt_l2cap_cid_predef { - L2CAP_CID_INVALID = 0x0000, - L2CAP_CID_SIGNALLING= 0x0001, - L2CAP_CID_GROUP = 0x0002, - L2CAP_CID_ALLOC = 0x0040, -}; - -/* L2CAP command codes */ -enum bt_l2cap_cmd { - L2CAP_COMMAND_REJ = 1, - L2CAP_CONN_REQ, - L2CAP_CONN_RSP, - L2CAP_CONF_REQ, - L2CAP_CONF_RSP, - L2CAP_DISCONN_REQ, - L2CAP_DISCONN_RSP, - L2CAP_ECHO_REQ, - L2CAP_ECHO_RSP, - L2CAP_INFO_REQ, - L2CAP_INFO_RSP, -}; - -enum bt_l2cap_sar_bits { - L2CAP_SAR_NO_SEG = 0, - L2CAP_SAR_START, - L2CAP_SAR_END, - L2CAP_SAR_CONT, -}; - -/* L2CAP structures */ -typedef struct { - uint16_t len; - uint16_t cid; - uint8_t data[0]; -} QEMU_PACKED l2cap_hdr; -#define L2CAP_HDR_SIZE 4 - -typedef struct { - uint8_t code; - uint8_t ident; - uint16_t len; -} QEMU_PACKED l2cap_cmd_hdr; -#define L2CAP_CMD_HDR_SIZE 4 - -typedef struct { - uint16_t reason; -} QEMU_PACKED l2cap_cmd_rej; -#define L2CAP_CMD_REJ_SIZE 2 - -typedef struct { - uint16_t dcid; - uint16_t scid; -} QEMU_PACKED l2cap_cmd_rej_cid; -#define L2CAP_CMD_REJ_CID_SIZE 4 - -/* reject reason */ -enum bt_l2cap_rej_reason { - L2CAP_REJ_CMD_NOT_UNDERSTOOD = 0, - L2CAP_REJ_SIG_TOOBIG, - L2CAP_REJ_CID_INVAL, -}; - -typedef struct { - uint16_t psm; - uint16_t scid; -} QEMU_PACKED l2cap_conn_req; -#define L2CAP_CONN_REQ_SIZE 4 - -typedef struct { - uint16_t dcid; - uint16_t scid; - uint16_t result; - uint16_t status; -} QEMU_PACKED l2cap_conn_rsp; -#define L2CAP_CONN_RSP_SIZE 8 - -/* connect result */ -enum bt_l2cap_conn_res { - L2CAP_CR_SUCCESS = 0, - L2CAP_CR_PEND, - L2CAP_CR_BAD_PSM, - L2CAP_CR_SEC_BLOCK, - L2CAP_CR_NO_MEM, -}; - -/* connect status */ -enum bt_l2cap_conn_stat { - L2CAP_CS_NO_INFO = 0, - L2CAP_CS_AUTHEN_PEND, - L2CAP_CS_AUTHOR_PEND, -}; - -typedef struct { - uint16_t dcid; - uint16_t flags; - uint8_t data[0]; -} QEMU_PACKED l2cap_conf_req; -#define L2CAP_CONF_REQ_SIZE(datalen) (4 + (datalen)) - -typedef struct { - uint16_t scid; - uint16_t flags; - uint16_t result; - uint8_t data[0]; -} QEMU_PACKED l2cap_conf_rsp; -#define L2CAP_CONF_RSP_SIZE(datalen) (6 + datalen) - -enum bt_l2cap_conf_res { - L2CAP_CONF_SUCCESS = 0, - L2CAP_CONF_UNACCEPT, - L2CAP_CONF_REJECT, - L2CAP_CONF_UNKNOWN, -}; - -typedef struct { - uint8_t type; - uint8_t len; - uint8_t val[0]; -} QEMU_PACKED l2cap_conf_opt; -#define L2CAP_CONF_OPT_SIZE 2 - -enum bt_l2cap_conf_val { - L2CAP_CONF_MTU = 1, - L2CAP_CONF_FLUSH_TO, - L2CAP_CONF_QOS, - L2CAP_CONF_RFC, - L2CAP_CONF_RFC_MODE = L2CAP_CONF_RFC, -}; - -typedef struct { - uint8_t flags; - uint8_t service_type; - uint32_t token_rate; - uint32_t token_bucket_size; - uint32_t peak_bandwidth; - uint32_t latency; - uint32_t delay_variation; -} QEMU_PACKED l2cap_conf_opt_qos; -#define L2CAP_CONF_OPT_QOS_SIZE 22 - -enum bt_l2cap_conf_opt_qos_st { - L2CAP_CONF_QOS_NO_TRAFFIC = 0x00, - L2CAP_CONF_QOS_BEST_EFFORT, - L2CAP_CONF_QOS_GUARANTEED, -}; - -#define L2CAP_CONF_QOS_WILDCARD 0xffffffff - -enum bt_l2cap_mode { - L2CAP_MODE_BASIC = 0, - L2CAP_MODE_RETRANS = 1, - L2CAP_MODE_FLOWCTL = 2, -}; - -typedef struct { - uint16_t dcid; - uint16_t scid; -} QEMU_PACKED l2cap_disconn_req; -#define L2CAP_DISCONN_REQ_SIZE 4 - -typedef struct { - uint16_t dcid; - uint16_t scid; -} QEMU_PACKED l2cap_disconn_rsp; -#define L2CAP_DISCONN_RSP_SIZE 4 - -typedef struct { - uint16_t type; -} QEMU_PACKED l2cap_info_req; -#define L2CAP_INFO_REQ_SIZE 2 - -typedef struct { - uint16_t type; - uint16_t result; - uint8_t data[0]; -} QEMU_PACKED l2cap_info_rsp; -#define L2CAP_INFO_RSP_SIZE 4 - -/* info type */ -enum bt_l2cap_info_type { - L2CAP_IT_CL_MTU = 1, - L2CAP_IT_FEAT_MASK, -}; - -/* info result */ -enum bt_l2cap_info_result { - L2CAP_IR_SUCCESS = 0, - L2CAP_IR_NOTSUPP, -}; - -/* Service Discovery Protocol defines */ -/* Note that all multibyte values in lower layer protocols (above in this file) - * are little-endian while SDP is big-endian. */ - -/* Protocol UUIDs */ -enum sdp_proto_uuid { - SDP_UUID = 0x0001, - UDP_UUID = 0x0002, - RFCOMM_UUID = 0x0003, - TCP_UUID = 0x0004, - TCS_BIN_UUID = 0x0005, - TCS_AT_UUID = 0x0006, - OBEX_UUID = 0x0008, - IP_UUID = 0x0009, - FTP_UUID = 0x000a, - HTTP_UUID = 0x000c, - WSP_UUID = 0x000e, - BNEP_UUID = 0x000f, - UPNP_UUID = 0x0010, - HIDP_UUID = 0x0011, - HCRP_CTRL_UUID = 0x0012, - HCRP_DATA_UUID = 0x0014, - HCRP_NOTE_UUID = 0x0016, - AVCTP_UUID = 0x0017, - AVDTP_UUID = 0x0019, - CMTP_UUID = 0x001b, - UDI_UUID = 0x001d, - MCAP_CTRL_UUID = 0x001e, - MCAP_DATA_UUID = 0x001f, - L2CAP_UUID = 0x0100, -}; - -/* - * Service class identifiers of standard services and service groups - */ -enum service_class_id { - SDP_SERVER_SVCLASS_ID = 0x1000, - BROWSE_GRP_DESC_SVCLASS_ID = 0x1001, - PUBLIC_BROWSE_GROUP = 0x1002, - SERIAL_PORT_SVCLASS_ID = 0x1101, - LAN_ACCESS_SVCLASS_ID = 0x1102, - DIALUP_NET_SVCLASS_ID = 0x1103, - IRMC_SYNC_SVCLASS_ID = 0x1104, - OBEX_OBJPUSH_SVCLASS_ID = 0x1105, - OBEX_FILETRANS_SVCLASS_ID = 0x1106, - IRMC_SYNC_CMD_SVCLASS_ID = 0x1107, - HEADSET_SVCLASS_ID = 0x1108, - CORDLESS_TELEPHONY_SVCLASS_ID = 0x1109, - AUDIO_SOURCE_SVCLASS_ID = 0x110a, - AUDIO_SINK_SVCLASS_ID = 0x110b, - AV_REMOTE_TARGET_SVCLASS_ID = 0x110c, - ADVANCED_AUDIO_SVCLASS_ID = 0x110d, - AV_REMOTE_SVCLASS_ID = 0x110e, - VIDEO_CONF_SVCLASS_ID = 0x110f, - INTERCOM_SVCLASS_ID = 0x1110, - FAX_SVCLASS_ID = 0x1111, - HEADSET_AGW_SVCLASS_ID = 0x1112, - WAP_SVCLASS_ID = 0x1113, - WAP_CLIENT_SVCLASS_ID = 0x1114, - PANU_SVCLASS_ID = 0x1115, - NAP_SVCLASS_ID = 0x1116, - GN_SVCLASS_ID = 0x1117, - DIRECT_PRINTING_SVCLASS_ID = 0x1118, - REFERENCE_PRINTING_SVCLASS_ID = 0x1119, - IMAGING_SVCLASS_ID = 0x111a, - IMAGING_RESPONDER_SVCLASS_ID = 0x111b, - IMAGING_ARCHIVE_SVCLASS_ID = 0x111c, - IMAGING_REFOBJS_SVCLASS_ID = 0x111d, - HANDSFREE_SVCLASS_ID = 0x111e, - HANDSFREE_AGW_SVCLASS_ID = 0x111f, - DIRECT_PRT_REFOBJS_SVCLASS_ID = 0x1120, - REFLECTED_UI_SVCLASS_ID = 0x1121, - BASIC_PRINTING_SVCLASS_ID = 0x1122, - PRINTING_STATUS_SVCLASS_ID = 0x1123, - HID_SVCLASS_ID = 0x1124, - HCR_SVCLASS_ID = 0x1125, - HCR_PRINT_SVCLASS_ID = 0x1126, - HCR_SCAN_SVCLASS_ID = 0x1127, - CIP_SVCLASS_ID = 0x1128, - VIDEO_CONF_GW_SVCLASS_ID = 0x1129, - UDI_MT_SVCLASS_ID = 0x112a, - UDI_TA_SVCLASS_ID = 0x112b, - AV_SVCLASS_ID = 0x112c, - SAP_SVCLASS_ID = 0x112d, - PBAP_PCE_SVCLASS_ID = 0x112e, - PBAP_PSE_SVCLASS_ID = 0x112f, - PBAP_SVCLASS_ID = 0x1130, - PNP_INFO_SVCLASS_ID = 0x1200, - GENERIC_NETWORKING_SVCLASS_ID = 0x1201, - GENERIC_FILETRANS_SVCLASS_ID = 0x1202, - GENERIC_AUDIO_SVCLASS_ID = 0x1203, - GENERIC_TELEPHONY_SVCLASS_ID = 0x1204, - UPNP_SVCLASS_ID = 0x1205, - UPNP_IP_SVCLASS_ID = 0x1206, - UPNP_PAN_SVCLASS_ID = 0x1300, - UPNP_LAP_SVCLASS_ID = 0x1301, - UPNP_L2CAP_SVCLASS_ID = 0x1302, - VIDEO_SOURCE_SVCLASS_ID = 0x1303, - VIDEO_SINK_SVCLASS_ID = 0x1304, - VIDEO_DISTRIBUTION_SVCLASS_ID = 0x1305, - MDP_SVCLASS_ID = 0x1400, - MDP_SOURCE_SVCLASS_ID = 0x1401, - MDP_SINK_SVCLASS_ID = 0x1402, - APPLE_AGENT_SVCLASS_ID = 0x2112, -}; - -/* - * Standard profile descriptor identifiers; note these - * may be identical to some of the service classes defined above - */ -#define SDP_SERVER_PROFILE_ID SDP_SERVER_SVCLASS_ID -#define BROWSE_GRP_DESC_PROFILE_ID BROWSE_GRP_DESC_SVCLASS_ID -#define SERIAL_PORT_PROFILE_ID SERIAL_PORT_SVCLASS_ID -#define LAN_ACCESS_PROFILE_ID LAN_ACCESS_SVCLASS_ID -#define DIALUP_NET_PROFILE_ID DIALUP_NET_SVCLASS_ID -#define IRMC_SYNC_PROFILE_ID IRMC_SYNC_SVCLASS_ID -#define OBEX_OBJPUSH_PROFILE_ID OBEX_OBJPUSH_SVCLASS_ID -#define OBEX_FILETRANS_PROFILE_ID OBEX_FILETRANS_SVCLASS_ID -#define IRMC_SYNC_CMD_PROFILE_ID IRMC_SYNC_CMD_SVCLASS_ID -#define HEADSET_PROFILE_ID HEADSET_SVCLASS_ID -#define CORDLESS_TELEPHONY_PROFILE_ID CORDLESS_TELEPHONY_SVCLASS_ID -#define AUDIO_SOURCE_PROFILE_ID AUDIO_SOURCE_SVCLASS_ID -#define AUDIO_SINK_PROFILE_ID AUDIO_SINK_SVCLASS_ID -#define AV_REMOTE_TARGET_PROFILE_ID AV_REMOTE_TARGET_SVCLASS_ID -#define ADVANCED_AUDIO_PROFILE_ID ADVANCED_AUDIO_SVCLASS_ID -#define AV_REMOTE_PROFILE_ID AV_REMOTE_SVCLASS_ID -#define VIDEO_CONF_PROFILE_ID VIDEO_CONF_SVCLASS_ID -#define INTERCOM_PROFILE_ID INTERCOM_SVCLASS_ID -#define FAX_PROFILE_ID FAX_SVCLASS_ID -#define HEADSET_AGW_PROFILE_ID HEADSET_AGW_SVCLASS_ID -#define WAP_PROFILE_ID WAP_SVCLASS_ID -#define WAP_CLIENT_PROFILE_ID WAP_CLIENT_SVCLASS_ID -#define PANU_PROFILE_ID PANU_SVCLASS_ID -#define NAP_PROFILE_ID NAP_SVCLASS_ID -#define GN_PROFILE_ID GN_SVCLASS_ID -#define DIRECT_PRINTING_PROFILE_ID DIRECT_PRINTING_SVCLASS_ID -#define REFERENCE_PRINTING_PROFILE_ID REFERENCE_PRINTING_SVCLASS_ID -#define IMAGING_PROFILE_ID IMAGING_SVCLASS_ID -#define IMAGING_RESPONDER_PROFILE_ID IMAGING_RESPONDER_SVCLASS_ID -#define IMAGING_ARCHIVE_PROFILE_ID IMAGING_ARCHIVE_SVCLASS_ID -#define IMAGING_REFOBJS_PROFILE_ID IMAGING_REFOBJS_SVCLASS_ID -#define HANDSFREE_PROFILE_ID HANDSFREE_SVCLASS_ID -#define HANDSFREE_AGW_PROFILE_ID HANDSFREE_AGW_SVCLASS_ID -#define DIRECT_PRT_REFOBJS_PROFILE_ID DIRECT_PRT_REFOBJS_SVCLASS_ID -#define REFLECTED_UI_PROFILE_ID REFLECTED_UI_SVCLASS_ID -#define BASIC_PRINTING_PROFILE_ID BASIC_PRINTING_SVCLASS_ID -#define PRINTING_STATUS_PROFILE_ID PRINTING_STATUS_SVCLASS_ID -#define HID_PROFILE_ID HID_SVCLASS_ID -#define HCR_PROFILE_ID HCR_SCAN_SVCLASS_ID -#define HCR_PRINT_PROFILE_ID HCR_PRINT_SVCLASS_ID -#define HCR_SCAN_PROFILE_ID HCR_SCAN_SVCLASS_ID -#define CIP_PROFILE_ID CIP_SVCLASS_ID -#define VIDEO_CONF_GW_PROFILE_ID VIDEO_CONF_GW_SVCLASS_ID -#define UDI_MT_PROFILE_ID UDI_MT_SVCLASS_ID -#define UDI_TA_PROFILE_ID UDI_TA_SVCLASS_ID -#define AV_PROFILE_ID AV_SVCLASS_ID -#define SAP_PROFILE_ID SAP_SVCLASS_ID -#define PBAP_PCE_PROFILE_ID PBAP_PCE_SVCLASS_ID -#define PBAP_PSE_PROFILE_ID PBAP_PSE_SVCLASS_ID -#define PBAP_PROFILE_ID PBAP_SVCLASS_ID -#define PNP_INFO_PROFILE_ID PNP_INFO_SVCLASS_ID -#define GENERIC_NETWORKING_PROFILE_ID GENERIC_NETWORKING_SVCLASS_ID -#define GENERIC_FILETRANS_PROFILE_ID GENERIC_FILETRANS_SVCLASS_ID -#define GENERIC_AUDIO_PROFILE_ID GENERIC_AUDIO_SVCLASS_ID -#define GENERIC_TELEPHONY_PROFILE_ID GENERIC_TELEPHONY_SVCLASS_ID -#define UPNP_PROFILE_ID UPNP_SVCLASS_ID -#define UPNP_IP_PROFILE_ID UPNP_IP_SVCLASS_ID -#define UPNP_PAN_PROFILE_ID UPNP_PAN_SVCLASS_ID -#define UPNP_LAP_PROFILE_ID UPNP_LAP_SVCLASS_ID -#define UPNP_L2CAP_PROFILE_ID UPNP_L2CAP_SVCLASS_ID -#define VIDEO_SOURCE_PROFILE_ID VIDEO_SOURCE_SVCLASS_ID -#define VIDEO_SINK_PROFILE_ID VIDEO_SINK_SVCLASS_ID -#define VIDEO_DISTRIBUTION_PROFILE_ID VIDEO_DISTRIBUTION_SVCLASS_ID -#define MDP_PROFILE_ID MDP_SVCLASS_ID -#define MDP_SOURCE_PROFILE_ID MDP_SROUCE_SVCLASS_ID -#define MDP_SINK_PROFILE_ID MDP_SINK_SVCLASS_ID -#define APPLE_AGENT_PROFILE_ID APPLE_AGENT_SVCLASS_ID - -/* Data Representation */ -enum bt_sdp_data_type { - SDP_DTYPE_NIL = 0 << 3, - SDP_DTYPE_UINT = 1 << 3, - SDP_DTYPE_SINT = 2 << 3, - SDP_DTYPE_UUID = 3 << 3, - SDP_DTYPE_STRING = 4 << 3, - SDP_DTYPE_BOOL = 5 << 3, - SDP_DTYPE_SEQ = 6 << 3, - SDP_DTYPE_ALT = 7 << 3, - SDP_DTYPE_URL = 8 << 3, -}; - -enum bt_sdp_data_size { - SDP_DSIZE_1 = 0, - SDP_DSIZE_2, - SDP_DSIZE_4, - SDP_DSIZE_8, - SDP_DSIZE_16, - SDP_DSIZE_NEXT1, - SDP_DSIZE_NEXT2, - SDP_DSIZE_NEXT4, - SDP_DSIZE_MASK = SDP_DSIZE_NEXT4, -}; - -enum bt_sdp_cmd { - SDP_ERROR_RSP = 0x01, - SDP_SVC_SEARCH_REQ = 0x02, - SDP_SVC_SEARCH_RSP = 0x03, - SDP_SVC_ATTR_REQ = 0x04, - SDP_SVC_ATTR_RSP = 0x05, - SDP_SVC_SEARCH_ATTR_REQ = 0x06, - SDP_SVC_SEARCH_ATTR_RSP = 0x07, -}; - -enum bt_sdp_errorcode { - SDP_INVALID_VERSION = 0x0001, - SDP_INVALID_RECORD_HANDLE = 0x0002, - SDP_INVALID_SYNTAX = 0x0003, - SDP_INVALID_PDU_SIZE = 0x0004, - SDP_INVALID_CSTATE = 0x0005, -}; - -/* - * String identifiers are based on the SDP spec stating that - * "base attribute id of the primary (universal) language must be 0x0100" - * - * Other languages should have their own offset; e.g.: - * #define XXXLangBase yyyy - * #define AttrServiceName_XXX 0x0000+XXXLangBase - */ -#define SDP_PRIMARY_LANG_BASE 0x0100 - -enum bt_sdp_attribute_id { - SDP_ATTR_RECORD_HANDLE = 0x0000, - SDP_ATTR_SVCLASS_ID_LIST = 0x0001, - SDP_ATTR_RECORD_STATE = 0x0002, - SDP_ATTR_SERVICE_ID = 0x0003, - SDP_ATTR_PROTO_DESC_LIST = 0x0004, - SDP_ATTR_BROWSE_GRP_LIST = 0x0005, - SDP_ATTR_LANG_BASE_ATTR_ID_LIST = 0x0006, - SDP_ATTR_SVCINFO_TTL = 0x0007, - SDP_ATTR_SERVICE_AVAILABILITY = 0x0008, - SDP_ATTR_PFILE_DESC_LIST = 0x0009, - SDP_ATTR_DOC_URL = 0x000a, - SDP_ATTR_CLNT_EXEC_URL = 0x000b, - SDP_ATTR_ICON_URL = 0x000c, - SDP_ATTR_ADD_PROTO_DESC_LIST = 0x000d, - - SDP_ATTR_SVCNAME_PRIMARY = SDP_PRIMARY_LANG_BASE + 0, - SDP_ATTR_SVCDESC_PRIMARY = SDP_PRIMARY_LANG_BASE + 1, - SDP_ATTR_SVCPROV_PRIMARY = SDP_PRIMARY_LANG_BASE + 2, - - SDP_ATTR_GROUP_ID = 0x0200, - SDP_ATTR_IP_SUBNET = 0x0200, - - /* SDP */ - SDP_ATTR_VERSION_NUM_LIST = 0x0200, - SDP_ATTR_SVCDB_STATE = 0x0201, - - SDP_ATTR_SERVICE_VERSION = 0x0300, - SDP_ATTR_EXTERNAL_NETWORK = 0x0301, - SDP_ATTR_SUPPORTED_DATA_STORES_LIST = 0x0301, - SDP_ATTR_FAX_CLASS1_SUPPORT = 0x0302, - SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL = 0x0302, - SDP_ATTR_FAX_CLASS20_SUPPORT = 0x0303, - SDP_ATTR_SUPPORTED_FORMATS_LIST = 0x0303, - SDP_ATTR_FAX_CLASS2_SUPPORT = 0x0304, - SDP_ATTR_AUDIO_FEEDBACK_SUPPORT = 0x0305, - SDP_ATTR_NETWORK_ADDRESS = 0x0306, - SDP_ATTR_WAP_GATEWAY = 0x0307, - SDP_ATTR_HOMEPAGE_URL = 0x0308, - SDP_ATTR_WAP_STACK_TYPE = 0x0309, - SDP_ATTR_SECURITY_DESC = 0x030a, - SDP_ATTR_NET_ACCESS_TYPE = 0x030b, - SDP_ATTR_MAX_NET_ACCESSRATE = 0x030c, - SDP_ATTR_IP4_SUBNET = 0x030d, - SDP_ATTR_IP6_SUBNET = 0x030e, - SDP_ATTR_SUPPORTED_CAPABILITIES = 0x0310, - SDP_ATTR_SUPPORTED_FEATURES = 0x0311, - SDP_ATTR_SUPPORTED_FUNCTIONS = 0x0312, - SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY = 0x0313, - SDP_ATTR_SUPPORTED_REPOSITORIES = 0x0314, - - /* PnP Information */ - SDP_ATTR_SPECIFICATION_ID = 0x0200, - SDP_ATTR_VENDOR_ID = 0x0201, - SDP_ATTR_PRODUCT_ID = 0x0202, - SDP_ATTR_VERSION = 0x0203, - SDP_ATTR_PRIMARY_RECORD = 0x0204, - SDP_ATTR_VENDOR_ID_SOURCE = 0x0205, - - /* BT HID */ - SDP_ATTR_DEVICE_RELEASE_NUMBER = 0x0200, - SDP_ATTR_PARSER_VERSION = 0x0201, - SDP_ATTR_DEVICE_SUBCLASS = 0x0202, - SDP_ATTR_COUNTRY_CODE = 0x0203, - SDP_ATTR_VIRTUAL_CABLE = 0x0204, - SDP_ATTR_RECONNECT_INITIATE = 0x0205, - SDP_ATTR_DESCRIPTOR_LIST = 0x0206, - SDP_ATTR_LANG_ID_BASE_LIST = 0x0207, - SDP_ATTR_SDP_DISABLE = 0x0208, - SDP_ATTR_BATTERY_POWER = 0x0209, - SDP_ATTR_REMOTE_WAKEUP = 0x020a, - SDP_ATTR_PROFILE_VERSION = 0x020b, - SDP_ATTR_SUPERVISION_TIMEOUT = 0x020c, - SDP_ATTR_NORMALLY_CONNECTABLE = 0x020d, - SDP_ATTR_BOOT_DEVICE = 0x020e, -}; - -#endif diff --git a/include/sysemu/bt.h b/include/sysemu/bt.h deleted file mode 100644 index 2fd8c0f14b..0000000000 --- a/include/sysemu/bt.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SYSEMU_BT_H -#define SYSEMU_BT_H - -/* BT HCI info */ - -typedef struct HCIInfo { - int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr); - void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len); - void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len); - void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, int len); - void *opaque; - void (*evt_recv)(void *opaque, const uint8_t *data, int len); - void (*acl_recv)(void *opaque, const uint8_t *data, int len); -} HCIInfo; - -/* bt-host.c */ -struct HCIInfo *bt_host_hci(const char *id); -struct HCIInfo *qemu_next_hci(void); - -#endif diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi index f909be56ae..62680f7bd5 100644 --- a/qemu-deprecated.texi +++ b/qemu-deprecated.texi @@ -242,13 +242,6 @@ via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs. @section System emulator devices -@subsection bluetooth (since 3.1) - -The bluetooth subsystem is unmaintained since many years and likely bitrotten -quite a bit. It will be removed without replacement unless some users speaks -up at the @email{qemu-devel@@nongnu.org} mailing list with information about -their usecases. - @subsection ide-drive (since 4.2) The 'ide-drive' device is deprecated. Users should use 'ide-hd' or diff --git a/qemu-options.hx b/qemu-options.hx index 3ff8c4e07a..c63e794b64 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3115,85 +3115,6 @@ STEXI ETEXI DEFHEADING() -DEFHEADING(Bluetooth(R) options:) -STEXI -@table @option -ETEXI - -DEF("bt", HAS_ARG, QEMU_OPTION_bt, \ - "-bt hci,null dumb bluetooth HCI - doesn't respond to commands\n" \ - "-bt hci,host[:id]\n" \ - " use host's HCI with the given name\n" \ - "-bt hci[,vlan=n]\n" \ - " emulate a standard HCI in virtual scatternet 'n'\n" \ - "-bt vhci[,vlan=n]\n" \ - " add host computer to virtual scatternet 'n' using VHCI\n" \ - "-bt device:dev[,vlan=n]\n" \ - " emulate a bluetooth device 'dev' in scatternet 'n'\n", - QEMU_ARCH_ALL) -STEXI -@item -bt hci[...] -@findex -bt -Defines the function of the corresponding Bluetooth HCI. -bt options -are matched with the HCIs present in the chosen machine type. For -example when emulating a machine with only one HCI built into it, only -the first @code{-bt hci[...]} option is valid and defines the HCI's -logic. The Transport Layer is decided by the machine type. Currently -the machines @code{n800} and @code{n810} have one HCI and all other -machines have none. - -Note: This option and the whole bluetooth subsystem is considered as deprecated. -If you still use it, please send a mail to @email{qemu-devel@@nongnu.org} where -you describe your usecase. - -@anchor{bt-hcis} -The following three types are recognized: - -@table @option -@item -bt hci,null -(default) The corresponding Bluetooth HCI assumes no internal logic -and will not respond to any HCI commands or emit events. - -@item -bt hci,host[:@var{id}] -(@code{bluez} only) The corresponding HCI passes commands / events -to / from the physical HCI identified by the name @var{id} (default: -@code{hci0}) on the computer running QEMU. Only available on @code{bluez} -capable systems like Linux. - -@item -bt hci[,vlan=@var{n}] -Add a virtual, standard HCI that will participate in the Bluetooth -scatternet @var{n} (default @code{0}). Similarly to @option{-net} -VLANs, devices inside a bluetooth network @var{n} can only communicate -with other devices in the same network (scatternet). -@end table - -@item -bt vhci[,vlan=@var{n}] -(Linux-host only) Create a HCI in scatternet @var{n} (default 0) attached -to the host bluetooth stack instead of to the emulated target. This -allows the host and target machines to participate in a common scatternet -and communicate. Requires the Linux @code{vhci} driver installed. Can -be used as following: - -@example -@value{qemu_system} [...OPTIONS...] -bt hci,vlan=5 -bt vhci,vlan=5 -@end example - -@item -bt device:@var{dev}[,vlan=@var{n}] -Emulate a bluetooth device @var{dev} and place it in network @var{n} -(default @code{0}). QEMU can only emulate one type of bluetooth devices -currently: - -@table @option -@item keyboard -Virtual wireless keyboard implementing the HIDP bluetooth profile. -@end table -ETEXI - -STEXI -@end table -ETEXI -DEFHEADING() - #ifdef CONFIG_TPM DEFHEADING(TPM device options:) @@ -62,14 +62,12 @@ int main(int argc, char **argv) #include "hw/isa/isa.h" #include "hw/scsi/scsi.h" #include "hw/display/vga.h" -#include "hw/bt.h" #include "sysemu/watchdog.h" #include "hw/firmware/smbios.h" #include "hw/acpi/acpi.h" #include "hw/xen/xen.h" #include "hw/loader.h" #include "monitor/qdev.h" -#include "sysemu/bt.h" #include "net/net.h" #include "net/slirp.h" #include "monitor/monitor.h" @@ -914,128 +912,6 @@ static void configure_rtc(QemuOpts *opts) } } -/***********************************************************/ -/* Bluetooth support */ -static int nb_hcis; -static int cur_hci; -static struct HCIInfo *hci_table[MAX_NICS]; - -struct HCIInfo *qemu_next_hci(void) -{ - if (cur_hci == nb_hcis) - return &null_hci; - - return hci_table[cur_hci++]; -} - -static int bt_hci_parse(const char *str) -{ - struct HCIInfo *hci; - bdaddr_t bdaddr; - - if (nb_hcis >= MAX_NICS) { - error_report("too many bluetooth HCIs (max %i)", MAX_NICS); - return -1; - } - - hci = hci_init(str); - if (!hci) - return -1; - - bdaddr.b[0] = 0x52; - bdaddr.b[1] = 0x54; - bdaddr.b[2] = 0x00; - bdaddr.b[3] = 0x12; - bdaddr.b[4] = 0x34; - bdaddr.b[5] = 0x56 + nb_hcis; - hci->bdaddr_set(hci, bdaddr.b); - - hci_table[nb_hcis++] = hci; - - return 0; -} - -static void bt_vhci_add(int vlan_id) -{ - struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id); - - if (!vlan->slave) - warn_report("adding a VHCI to an empty scatternet %i", - vlan_id); - - bt_vhci_init(bt_new_hci(vlan)); -} - -static struct bt_device_s *bt_device_add(const char *opt) -{ - struct bt_scatternet_s *vlan; - int vlan_id = 0; - char *endp = strstr(opt, ",vlan="); - int len = (endp ? endp - opt : strlen(opt)) + 1; - char devname[10]; - - pstrcpy(devname, MIN(sizeof(devname), len), opt); - - if (endp) { - vlan_id = strtol(endp + 6, &endp, 0); - if (*endp) { - error_report("unrecognised bluetooth vlan Id"); - return 0; - } - } - - vlan = qemu_find_bt_vlan(vlan_id); - - if (!vlan->slave) - warn_report("adding a slave device to an empty scatternet %i", - vlan_id); - - if (!strcmp(devname, "keyboard")) - return bt_keyboard_init(vlan); - - error_report("unsupported bluetooth device '%s'", devname); - return 0; -} - -static int bt_parse(const char *opt) -{ - const char *endp, *p; - int vlan; - - if (strstart(opt, "hci", &endp)) { - if (!*endp || *endp == ',') { - if (*endp) - if (!strstart(endp, ",vlan=", 0)) - opt = endp + 1; - - return bt_hci_parse(opt); - } - } else if (strstart(opt, "vhci", &endp)) { - if (!*endp || *endp == ',') { - if (*endp) { - if (strstart(endp, ",vlan=", &p)) { - vlan = strtol(p, (char **) &endp, 0); - if (*endp) { - error_report("bad scatternet '%s'", p); - return 1; - } - } else { - error_report("bad parameter '%s'", endp + 1); - return 1; - } - } else - vlan = 0; - - bt_vhci_add(vlan); - return 0; - } - } else if (strstart(opt, "device:", &endp)) - return !bt_device_add(endp); - - error_report("bad bluetooth parameter '%s'", opt); - return 1; -} - static int parse_name(void *opaque, QemuOpts *opts, Error **errp) { const char *proc_name; @@ -2319,7 +2195,6 @@ static void monitor_parse(const char *optarg, const char *mode, bool pretty) struct device_config { enum { DEV_USB, /* -usbdevice */ - DEV_BT, /* -bt */ DEV_SERIAL, /* -serial */ DEV_PARALLEL, /* -parallel */ DEV_DEBUGCON, /* -debugcon */ @@ -3128,13 +3003,6 @@ int main(int argc, char **argv, char **envp) } break; #endif - case QEMU_OPTION_bt: - warn_report("The bluetooth subsystem is deprecated and will " - "be removed soon. If the bluetooth subsystem is " - "still useful for you, please send a mail to " - "qemu-devel@nongnu.org with your usecase."); - add_device_config(DEV_BT, optarg); - break; case QEMU_OPTION_audio_help: audio_legacy_help(); exit (0); @@ -4259,10 +4127,6 @@ int main(int argc, char **argv, char **envp) tpm_init(); - /* init the bluetooth world */ - if (foreach_device_config(DEV_BT, bt_parse)) - exit(1); - if (!xen_enabled()) { /* On 32-bit hosts, QEMU is limited by virtual address space */ if (ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { |