diff options
author | 2014-07-11 21:54:37 +0000 | |
---|---|---|
committer | 2014-07-11 21:54:37 +0000 | |
commit | b8042ed98e3e7a691133b4fd8e91f61ba15a83ba (patch) | |
tree | b4210de9bc12a180e816fe8ce2bb3606f14cb4f4 | |
parent | sync (diff) | |
download | wireguard-openbsd-b8042ed98e3e7a691133b4fd8e91f61ba15a83ba.tar.xz wireguard-openbsd-b8042ed98e3e7a691133b4fd8e91f61ba15a83ba.zip |
"It's not the years, honey; it's the mileage."
bluetooth support doesn't work and isn't going anywhere. the current
design is a dead end, and should not be the basis for any future support.
general consensus says to whack it so as to not mislead the unwary.
57 files changed, 19 insertions, 19835 deletions
diff --git a/sys/arch/alpha/conf/files.alpha b/sys/arch/alpha/conf/files.alpha index 7182b685a10..306add1ac68 100644 --- a/sys/arch/alpha/conf/files.alpha +++ b/sys/arch/alpha/conf/files.alpha @@ -1,4 +1,4 @@ -# $OpenBSD: files.alpha,v 1.98 2014/01/26 17:40:11 miod Exp $ +# $OpenBSD: files.alpha,v 1.99 2014/07/11 21:54:37 tedu Exp $ # $NetBSD: files.alpha,v 1.32 1996/11/25 04:03:21 cgd Exp $ # # alpha-specific configuration info @@ -352,11 +352,6 @@ include "dev/i2c/files.i2c" include "dev/usb/files.usb" # -# Bluetooth -# -include "dev/bluetooth/files.bluetooth" - -# # Machine-independent 1-Wire drivers # include "dev/onewire/files.onewire" diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64 index f283f4c50fc..e1cd6fa6d6b 100644 --- a/sys/arch/amd64/conf/files.amd64 +++ b/sys/arch/amd64/conf/files.amd64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.amd64,v 1.73 2013/12/19 21:30:02 deraadt Exp $ +# $OpenBSD: files.amd64,v 1.74 2014/07/11 21:54:37 tedu Exp $ maxpartitions 16 maxusers 2 16 128 @@ -205,11 +205,6 @@ file arch/amd64/amd64/nvram.c nvram needs-flag include "dev/usb/files.usb" # -# Bluetooth -# -include "dev/bluetooth/files.bluetooth" - -# # I2C # include "dev/i2c/files.i2c" diff --git a/sys/arch/armish/conf/files.armish b/sys/arch/armish/conf/files.armish index 186f47d5a31..539fd8f1a5d 100644 --- a/sys/arch/armish/conf/files.armish +++ b/sys/arch/armish/conf/files.armish @@ -1,4 +1,4 @@ -# $OpenBSD: files.armish,v 1.16 2013/11/04 14:07:15 deraadt Exp $ +# $OpenBSD: files.armish,v 1.17 2014/07/11 21:54:37 tedu Exp $ maxpartitions 16 maxusers 2 8 64 @@ -57,9 +57,6 @@ include "dev/rasops/files.rasops" # Include USB stuff include "dev/usb/files.usb" -# Bluetooth -include "dev/bluetooth/files.bluetooth" - # Media Independent Interface (mii) include "dev/mii/files.mii" diff --git a/sys/arch/armv7/conf/files.armv7 b/sys/arch/armv7/conf/files.armv7 index b379a4bebe7..acdea23b479 100644 --- a/sys/arch/armv7/conf/files.armv7 +++ b/sys/arch/armv7/conf/files.armv7 @@ -1,4 +1,4 @@ -# $OpenBSD: files.armv7,v 1.9 2013/11/06 19:03:07 syl Exp $ +# $OpenBSD: files.armv7,v 1.10 2014/07/11 21:54:37 tedu Exp $ maxpartitions 16 maxusers 2 8 64 @@ -49,9 +49,6 @@ include "dev/wsfont/files.wsfont" # Include USB stuff include "dev/usb/files.usb" -# Bluetooth -include "dev/bluetooth/files.bluetooth" - # Machine-independent GPIO drivers include "dev/gpio/files.gpio" diff --git a/sys/arch/hppa/conf/files.hppa b/sys/arch/hppa/conf/files.hppa index cf2f13bc9aa..041bb7b97e8 100644 --- a/sys/arch/hppa/conf/files.hppa +++ b/sys/arch/hppa/conf/files.hppa @@ -1,4 +1,4 @@ -# $OpenBSD: files.hppa,v 1.91 2013/11/04 14:07:16 deraadt Exp $ +# $OpenBSD: files.hppa,v 1.92 2014/07/11 21:54:37 tedu Exp $ # # hppa-specific configuration info @@ -73,11 +73,6 @@ include "dev/pcmcia/files.pcmcia" include "dev/usb/files.usb" # -# Bluetooth -# -include "dev/bluetooth/files.bluetooth" - -# # HIL Human Interface Loop devices # include "dev/hil/files.hil" diff --git a/sys/arch/hppa64/conf/files.hppa64 b/sys/arch/hppa64/conf/files.hppa64 index 14093cb1a41..a3454a97b04 100644 --- a/sys/arch/hppa64/conf/files.hppa64 +++ b/sys/arch/hppa64/conf/files.hppa64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.hppa64,v 1.17 2013/11/04 14:07:16 deraadt Exp $ +# $OpenBSD: files.hppa64,v 1.18 2014/07/11 21:54:37 tedu Exp $ # # hppa64-specific configuration info @@ -53,11 +53,6 @@ include "dev/pcmcia/files.pcmcia" include "dev/usb/files.usb" # -# Bluetooth -# -include "dev/bluetooth/files.bluetooth" - -# # Machine-independent 1-Wire drivers # include "dev/onewire/files.onewire" diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 2f234fa0bc5..164bcf6081b 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.216 2013/12/19 21:30:02 deraadt Exp $ +# $OpenBSD: files.i386,v 1.217 2014/07/11 21:54:37 tedu Exp $ # # new style config file for i386 architecture # @@ -389,11 +389,6 @@ include "dev/onewire/files.onewire" # include "dev/sdmmc/files.sdmmc" -# -# Machine-independent Bluetooth drivers -# -include "dev/bluetooth/files.bluetooth" - include "dev/acpi/files.acpi" file arch/i386/i386/acpi_machdep.c acpi file arch/i386/i386/acpi_wakecode.S acpi & !small_kernel diff --git a/sys/arch/landisk/conf/files.landisk b/sys/arch/landisk/conf/files.landisk index 39f7754d9b8..dc862dfff19 100644 --- a/sys/arch/landisk/conf/files.landisk +++ b/sys/arch/landisk/conf/files.landisk @@ -1,4 +1,4 @@ -# $OpenBSD: files.landisk,v 1.9 2013/11/04 14:07:16 deraadt Exp $ +# $OpenBSD: files.landisk,v 1.10 2014/07/11 21:54:37 tedu Exp $ # $NetBSD: files.landisk,v 1.2 2006/09/07 01:55:02 uwe Exp $ # maxpartitions must be first item in files.${MACHINE} @@ -66,11 +66,6 @@ include "dev/rasops/files.rasops" include "dev/usb/files.usb" # -# Bluetooth -# -include "dev/bluetooth/files.bluetooth" - -# # SH bus # include "arch/sh/conf/files.shb" diff --git a/sys/arch/loongson/conf/files.loongson b/sys/arch/loongson/conf/files.loongson index 46b668181c5..aca9bbb9611 100644 --- a/sys/arch/loongson/conf/files.loongson +++ b/sys/arch/loongson/conf/files.loongson @@ -1,4 +1,4 @@ -# $OpenBSD: files.loongson,v 1.17 2013/11/04 14:07:16 deraadt Exp $ +# $OpenBSD: files.loongson,v 1.18 2014/07/11 21:54:37 tedu Exp $ # Standard stanzas config(8) can't run without maxpartitions 16 @@ -40,7 +40,6 @@ include "dev/mii/files.mii" include "dev/pci/files.pci" include "dev/pckbc/files.pckbc" include "dev/usb/files.usb" -include "dev/bluetooth/files.bluetooth" include "dev/rasops/files.rasops" include "dev/wscons/files.wscons" include "dev/wsfont/files.wsfont" diff --git a/sys/arch/macppc/conf/files.macppc b/sys/arch/macppc/conf/files.macppc index 4cc93ec16e5..8ebb630cb96 100644 --- a/sys/arch/macppc/conf/files.macppc +++ b/sys/arch/macppc/conf/files.macppc @@ -1,4 +1,4 @@ -# $OpenBSD: files.macppc,v 1.77 2013/11/04 14:07:16 deraadt Exp $ +# $OpenBSD: files.macppc,v 1.78 2014/07/11 21:54:37 tedu Exp $ # # macppc-specific configuration info @@ -270,11 +270,6 @@ include "dev/pcmcia/files.pcmcia" include "dev/usb/files.usb" # -# Bluetooth -# -include "dev/bluetooth/files.bluetooth" - -# # Machine-independent I2C drivers # include "dev/i2c/files.i2c" diff --git a/sys/arch/octeon/conf/files.octeon b/sys/arch/octeon/conf/files.octeon index 13de7f1a01d..d8b9ea68b5c 100644 --- a/sys/arch/octeon/conf/files.octeon +++ b/sys/arch/octeon/conf/files.octeon @@ -1,4 +1,4 @@ -# $OpenBSD: files.octeon,v 1.18 2014/07/09 23:03:22 pirofti Exp $ +# $OpenBSD: files.octeon,v 1.19 2014/07/11 21:54:38 tedu Exp $ # Standard stanzas config(8) can't run without maxpartitions 16 @@ -31,7 +31,6 @@ include "dev/mii/files.mii" include "dev/pci/files.pci" include "dev/pckbc/files.pckbc" include "dev/usb/files.usb" -include "dev/bluetooth/files.bluetooth" include "dev/rasops/files.rasops" include "dev/wscons/files.wscons" include "dev/wsfont/files.wsfont" diff --git a/sys/arch/socppc/conf/files.socppc b/sys/arch/socppc/conf/files.socppc index 6b462634a1e..b4a5739331a 100644 --- a/sys/arch/socppc/conf/files.socppc +++ b/sys/arch/socppc/conf/files.socppc @@ -1,4 +1,4 @@ -# $OpenBSD: files.socppc,v 1.11 2013/11/04 14:07:16 deraadt Exp $ +# $OpenBSD: files.socppc,v 1.12 2014/07/11 21:54:38 tedu Exp $ # # macppc-specific configuration info @@ -101,11 +101,6 @@ attach ehci at obio with ehci_obio file arch/socppc/dev/ehci_obio.c ehci # -# Bluetooth -# -include "dev/bluetooth/files.bluetooth" - -# # Machine-independent I2C drivers # include "dev/i2c/files.i2c" diff --git a/sys/arch/sparc64/conf/files.sparc64 b/sys/arch/sparc64/conf/files.sparc64 index 94f61781f63..bc0f1b287fc 100644 --- a/sys/arch/sparc64/conf/files.sparc64 +++ b/sys/arch/sparc64/conf/files.sparc64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.sparc64,v 1.144 2013/11/04 14:07:16 deraadt Exp $ +# $OpenBSD: files.sparc64,v 1.145 2014/07/11 21:54:38 tedu Exp $ # $NetBSD: files.sparc64,v 1.50 2001/08/10 20:53:50 eeh Exp $ # maxpartitions must be first item in files.${ARCH} @@ -370,11 +370,6 @@ include "dev/sdmmc/files.sdmmc" include "dev/usb/files.usb" # -# Bluetooth -# -include "dev/bluetooth/files.bluetooth" - -# # Cardbus # include "dev/cardbus/files.cardbus" diff --git a/sys/arch/zaurus/conf/files.zaurus b/sys/arch/zaurus/conf/files.zaurus index d77cf92ce11..e58f21fb710 100644 --- a/sys/arch/zaurus/conf/files.zaurus +++ b/sys/arch/zaurus/conf/files.zaurus @@ -1,4 +1,4 @@ -# $OpenBSD: files.zaurus,v 1.28 2013/11/04 14:07:16 deraadt Exp $ +# $OpenBSD: files.zaurus,v 1.29 2014/07/11 21:54:38 tedu Exp $ # # First try for arm-specific configuration info # @@ -100,8 +100,6 @@ include "dev/usb/files.usb" attach pxaudc at pxaip with pxaudc_zaurus file arch/zaurus/dev/zaurus_udc.c pxaudc_zaurus -# Bluetooth -include "dev/bluetooth/files.bluetooth" # Media Independent Interface (mii) include "dev/mii/files.mii" diff --git a/sys/conf/files b/sys/conf/files index e4771b9e4cb..ae98d65ba19 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.572 2014/04/19 12:27:06 henning Exp $ +# $OpenBSD: files,v 1.573 2014/07/11 21:54:38 tedu Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -67,7 +67,6 @@ define systrace define ether define sppp define wlan -define bluetooth # "Chipset" attributes. These are the machine-independent portions # of device drivers. @@ -884,25 +883,6 @@ file crypto/hmac.c wlan | (softraid & crypto) file crypto/gmac.c (inet & ipsec) | crypto file crypto/key_wrap.c wlan file crypto/idgen.c inet6 | nfsclient | nfsserver -file netbt/bt_input.c bluetooth needs-flag -file netbt/bt_proto.c bluetooth -file netbt/hci_event.c bluetooth -file netbt/hci_ioctl.c bluetooth -file netbt/hci_link.c bluetooth -file netbt/hci_misc.c bluetooth -file netbt/hci_socket.c bluetooth -file netbt/hci_unit.c bluetooth -file netbt/l2cap_lower.c bluetooth -file netbt/l2cap_misc.c bluetooth -file netbt/l2cap_signal.c bluetooth -file netbt/l2cap_socket.c bluetooth -file netbt/l2cap_upper.c bluetooth -file netbt/rfcomm_dlc.c bluetooth -file netbt/rfcomm_session.c bluetooth -file netbt/rfcomm_socket.c bluetooth -file netbt/rfcomm_upper.c bluetooth -file netbt/sco_socket.c bluetooth -file netbt/sco_upper.c bluetooth file netmpls/mpls_input.c mpls file netmpls/mpls_output.c mpls file netmpls/mpls_proto.c mpls diff --git a/sys/dev/bluetooth/btdev.h b/sys/dev/bluetooth/btdev.h deleted file mode 100644 index a559f30921f..00000000000 --- a/sys/dev/bluetooth/btdev.h +++ /dev/null @@ -1,112 +0,0 @@ -/* $OpenBSD: btdev.h,v 1.5 2008/11/24 23:54:03 uwe Exp $ */ -/* $NetBSD: btdev.h,v 1.1 2006/06/19 15:44:45 gdamore Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _DEV_BLUETOOTH_BTDEV_H_ -#define _DEV_BLUETOOTH_BTDEV_H_ - -#include <netbt/bluetooth.h> - -/* - * Bluetooth Device attach arguments (from userland) - */ -struct btdev_attach_args { - bdaddr_t bd_laddr; /* local address */ - bdaddr_t bd_raddr; /* remote address */ - uint16_t bd_type; /* device type */ - int bd_mode; /* link mode */ - - union { - struct { /* HID arguments */ - uint16_t hid_flags;/* HID flags */ - uint16_t hid_ctl; /* control PSM */ - uint16_t hid_int; /* interrupt PSM */ - void *hid_desc; /* HID descriptor */ - uint16_t hid_dlen; /* descriptor length */ - } bdd_hid; - - struct { /* HSET arguments */ - uint8_t hset_channel; /* RFCOMM channel */ - uint8_t hset_mtu; /* SCO mtu */ - int hset_listen; /* connect or listen */ - } bdd_hset; - - struct { /* HF arguments */ - uint8_t hf_channel; /* RFCOMM channel */ - uint8_t hf_mtu; /* SCO mtu */ - int hf_listen; /* connect or listen */ - } bdd_hf; - } bdd; -}; - -#define bd_hid bdd.bdd_hid -#define bd_hset bdd.bdd_hset -#define bd_hf bdd.bdd_hf - -/* btdev type */ -#define BTDEV_NONE 0x0000 -#define BTDEV_HID 0x0001 -#define BTDEV_HSET 0x0002 -#define BTDEV_HF 0x0003 - -/* btdev link mode */ -#define BTDEV_MODE_NONE 0 -#define BTDEV_MODE_AUTH 1 -#define BTDEV_MODE_ENCRYPT 2 -#define BTDEV_MODE_SECURE 3 - -/* bthid flags */ -#define BTHID_INITIATE (1 << 0) /* normally initiate */ - -/* btdev attach/detach ioctl's */ -#define BTDEV_ATTACH _IOW('b', 14, struct btdev_attach_args) -#define BTDEV_DETACH _IOW('b', 15, struct btdev_attach_args) - -#ifdef _KERNEL - -/* - * Bluetooth device header - */ -struct btdev { - struct device sc_dev; /* system device */ - bdaddr_t sc_addr; /* device bdaddr */ - uint16_t sc_type; /* device type */ - - LIST_ENTRY(btdev) sc_next; -}; - -#define btdev_name(d) (((struct btdev *)(d))->sc_dev.dv_xname) - -#endif /* _KERNEL */ - -#endif /* _DEV_BLUETOOTH_BTDEV_H_ */ diff --git a/sys/dev/bluetooth/bthid.h b/sys/dev/bluetooth/bthid.h deleted file mode 100644 index 0b0e2046280..00000000000 --- a/sys/dev/bluetooth/bthid.h +++ /dev/null @@ -1,90 +0,0 @@ -/* $OpenBSD: bthid.h,v 1.1 2007/07/27 16:52:24 gwk Exp $ */ -/* $NetBSD: bthid.h,v 1.1 2006/06/19 15:44:45 gdamore Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _DEV_BLUETOOTH_BTHID_H_ -#define _DEV_BLUETOOTH_BTHID_H_ - -/* Transaction Types */ -#define BTHID_HANDSHAKE 0x0 -#define BTHID_CONTROL 0x1 -#define BTHID_GET_REPORT 0x4 -#define BTHID_SET_REPORT 0x5 -#define BTHID_GET_PROTOCOL 0x6 -#define BTHID_SET_PROTOCOL 0x7 -#define BTHID_GET_IDLE 0x8 -#define BTHID_SET_IDLE 0x9 -#define BTHID_DATA 0xa -#define BTHID_DATC 0xb - -#define BTHID_TYPE(b) (((b) & 0xf0) >> 4) - -/* HANDSHAKE Transaction Parameters */ -#define BTHID_HANDSHAKE_SUCCESS 0x0 -#define BTHID_HANDSHAKE_NOT_READY 0x1 -#define BTHID_HANDSHAKE_INVALID_ID 0x2 -#define BTHID_HANDSHAKE_UNSUPPORTED 0x3 -#define BTHID_HANDSHAKE_INVALID_PARAM 0x4 -#define BTHID_HANDSHAKE_UNKNOWN 0xe -#define BTHID_HANDSHAKE_FATAL 0xf - -#define BTHID_HANDSHAKE_PARAM(b) ((b) & 0x0f) - -/* HID_CONTROL Transaction Parameters */ -#define BTHID_CONTROL_NOP 0x0 -#define BTHID_CONTROL_HARD_RESET 0x1 -#define BTHID_CONTROL_SOFT_RESET 0x2 -#define BTHID_CONTROL_SUSPEND 0x3 -#define BTHID_CONTROL_RESUME 0x4 -#define BTHID_CONTROL_UNPLUG 0x5 - -#define BTHID_CONTROL_PARAM(b) ((b) & 0x0f) - -/* GET_REPORT Transaction Parameters */ -#define BTHID_CONTROL_SIZE 0x08 - -/* GET_PROTOCOL Transaction Parameters */ -#define BTHID_PROTOCOL_REPORT 0 -#define BTHID_PROTOCOL_BOOT 1 - -#define BTHID_PROTOCOL_PARAM(b) ((b) & 0x01) - -/* DATA, DATC Transaction Parameters */ -#define BTHID_DATA_OTHER 0 -#define BTHID_DATA_INPUT 1 -#define BTHID_DATA_OUTPUT 2 -#define BTHID_DATA_FEATURE 3 - -#define BTHID_DATA_PARAM(b) ((b) & 0x03) - -#endif /* _DEV_BLUETOOTH_BTHID_H_ */ diff --git a/sys/dev/bluetooth/bthidev.c b/sys/dev/bluetooth/bthidev.c deleted file mode 100644 index 11b3b277a6e..00000000000 --- a/sys/dev/bluetooth/bthidev.c +++ /dev/null @@ -1,903 +0,0 @@ -/* $OpenBSD: bthidev.c,v 1.9 2011/06/17 07:06:46 mk Exp $ */ -/* $NetBSD: bthidev.c,v 1.16 2008/08/06 15:01:23 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/conf.h> -#include <sys/device.h> -#include <sys/fcntl.h> -#include <sys/kernel.h> -#include <sys/queue.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/l2cap.h> - -#include <dev/usb/hid.h> -#include <dev/bluetooth/btdev.h> -#include <dev/bluetooth/bthid.h> -#include <dev/bluetooth/bthidev.h> - -#define MAX_DESCRIPTOR_LEN 1024 /* sanity check */ - -/* bthidev softc */ -struct bthidev_softc { - struct btdev sc_btdev; /* base device */ - uint16_t sc_state; - uint16_t sc_flags; - - bdaddr_t sc_laddr; /* local address */ - bdaddr_t sc_raddr; /* remote address */ - int sc_mode; /* link mode */ - void *sc_desc; /* HID descriptor */ - int sc_dlen; /* descriptor length */ - - uint16_t sc_ctlpsm; /* control PSM */ - struct l2cap_channel *sc_ctl; /* control channel */ - struct l2cap_channel *sc_ctl_l; /* control listen */ - - uint16_t sc_intpsm; /* interrupt PSM */ - struct l2cap_channel *sc_int; /* interrupt channel */ - struct l2cap_channel *sc_int_l; /* interrupt listen */ - - LIST_HEAD(,bthidev) sc_list; /* child list */ - - struct timeout sc_reconnect; - int sc_attempts; /* connection attempts */ -}; - -/* sc_flags */ -#define BTHID_RECONNECT (1 << 0) /* reconnect on link loss */ -#define BTHID_CONNECTING (1 << 1) /* we are connecting */ - -/* device state */ -#define BTHID_CLOSED 0 -#define BTHID_WAIT_CTL 1 -#define BTHID_WAIT_INT 2 -#define BTHID_OPEN 3 - -#define BTHID_RETRY_INTERVAL 5 /* seconds between connection attempts */ - -/* bthidev internals */ -void bthidev_timeout(void *); -int bthidev_listen(struct bthidev_softc *); -int bthidev_connect(struct bthidev_softc *); -int bthidev_output(struct bthidev *, uint8_t *, int, int); -void bthidev_null(struct bthidev *, uint8_t *, int); - -/* autoconf(9) glue */ -int bthidev_match(struct device *, void *, void *); -void bthidev_attach(struct device *, struct device *, void *); -int bthidev_detach(struct device *, int); -int bthidev_print(void *, const char *); - -int bthidevsubmatch(struct device *parent, void *, void *); - -struct cfdriver bthidev_cd = { - NULL, "bthidev", DV_DULL -}; - -const struct cfattach bthidev_ca = { - sizeof(struct bthidev_softc), - bthidev_match, - bthidev_attach, - bthidev_detach, -}; - -/* bluetooth(9) protocol methods for L2CAP */ -void bthidev_connecting(void *); -void bthidev_ctl_connected(void *); -void bthidev_int_connected(void *); -void bthidev_ctl_disconnected(void *, int); -void bthidev_int_disconnected(void *, int); -void *bthidev_ctl_newconn(void *, struct sockaddr_bt *, - struct sockaddr_bt *); -void *bthidev_int_newconn(void *, struct sockaddr_bt *, - struct sockaddr_bt *); -void bthidev_complete(void *, int); -void bthidev_linkmode(void *, int); -void bthidev_input(void *, struct mbuf *); - -const struct btproto bthidev_ctl_proto = { - bthidev_connecting, - bthidev_ctl_connected, - bthidev_ctl_disconnected, - bthidev_ctl_newconn, - bthidev_complete, - bthidev_linkmode, - bthidev_input, -}; - -const struct btproto bthidev_int_proto = { - bthidev_connecting, - bthidev_int_connected, - bthidev_int_disconnected, - bthidev_int_newconn, - bthidev_complete, - bthidev_linkmode, - bthidev_input, -}; - -/***************************************************************************** - * - * bthidev autoconf(9) routines - */ - -int -bthidev_match(struct device *self, void *match, void *aux) -{ - struct btdev_attach_args *bda = (struct btdev_attach_args *)aux; - - if (bda->bd_type != BTDEV_HID) - return 0; - - return 1; -} - -void -bthidev_attach(struct device *parent, struct device *self, void *aux) -{ - struct bthidev_softc *sc = (struct bthidev_softc *)self; - struct btdev_attach_args *bda = (struct btdev_attach_args *)aux; - struct bthidev_attach_args bha; - struct bthidev *hidev; - struct hid_data *d; - struct hid_item h; - int maxid, rep; - - /* - * Init softc - */ - LIST_INIT(&sc->sc_list); - timeout_set(&sc->sc_reconnect, bthidev_timeout, sc); - sc->sc_state = BTHID_CLOSED; - sc->sc_flags = BTHID_CONNECTING; - sc->sc_ctlpsm = L2CAP_PSM_HID_CNTL; - sc->sc_intpsm = L2CAP_PSM_HID_INTR; - - sc->sc_mode = 0; - - /* - * copy in our configuration info - */ - bdaddr_copy(&sc->sc_laddr, &bda->bd_laddr); - bdaddr_copy(&sc->sc_raddr, &bda->bd_raddr); - - if (bda->bd_mode != BTDEV_MODE_NONE) { - if (bda->bd_mode == BTDEV_MODE_AUTH) { - sc->sc_mode = L2CAP_LM_AUTH; - printf(" auth"); - } else if (bda->bd_mode == BTDEV_MODE_ENCRYPT) { - sc->sc_mode = L2CAP_LM_ENCRYPT; - printf(" encrypt"); - } else if (bda->bd_mode == BTDEV_MODE_SECURE) { - sc->sc_mode = L2CAP_LM_SECURE; - printf(" secure"); - } else { - printf(" unknown link-mode: %d\n", bda->bd_mode); - return; - } - } - - if (!L2CAP_PSM_INVALID(bda->bd_hid.hid_ctl)) - sc->sc_ctlpsm = bda->bd_hid.hid_ctl; - - if (!L2CAP_PSM_INVALID(bda->bd_hid.hid_int)) - sc->sc_intpsm = bda->bd_hid.hid_int; - - if (bda->bd_hid.hid_flags & BTHID_INITIATE) - sc->sc_flags |= BTHID_RECONNECT; - - if (bda->bd_hid.hid_desc == NULL || - bda->bd_hid.hid_dlen == 0 || - bda->bd_hid.hid_dlen > MAX_DESCRIPTOR_LEN) { - printf(": no descriptor\n"); - return; - } - sc->sc_dlen = bda->bd_hid.hid_dlen; - sc->sc_desc = malloc(bda->bd_hid.hid_dlen, M_BTHIDEV, - M_WAITOK | M_CANFAIL); - if (sc->sc_desc == NULL) { - printf(": no memory\n"); - return; - } - if (copyin(bda->bd_hid.hid_desc, sc->sc_desc, bda->bd_hid.hid_dlen)) { - free(sc->sc_desc, M_BTHIDEV); - printf(": no descriptor"); - return; - } - - /* - * Parse the descriptor and attach child devices, one per report. - */ - maxid = -1; - h.report_ID = 0; - d = hid_start_parse(sc->sc_desc, sc->sc_dlen, hid_none); - while (hid_get_item(d, &h)) { - if (h.report_ID > maxid) - maxid = h.report_ID; - } - hid_end_parse(d); - - if (maxid < 0) { - printf(": no reports found\n"); - return; - } - - printf("\n"); - - for (rep = 0 ; rep <= maxid ; rep++) { - if (hid_report_size(sc->sc_desc, sc->sc_dlen, hid_feature, rep) == 0 - && hid_report_size(sc->sc_desc, sc->sc_dlen, hid_input, rep) == 0 - && hid_report_size(sc->sc_desc, sc->sc_dlen, hid_output, rep) == 0) - continue; - - bha.ba_desc = sc->sc_desc; - bha.ba_dlen = sc->sc_dlen; - bha.ba_input = bthidev_null; - bha.ba_feature = bthidev_null; - bha.ba_output = bthidev_output; - bha.ba_id = rep; - - hidev = (struct bthidev *)config_found_sm(self, &bha, - bthidev_print, bthidevsubmatch); - if (hidev != NULL) { - hidev->sc_parent = &sc->sc_btdev; - hidev->sc_id = rep; - hidev->sc_input = bha.ba_input; - hidev->sc_feature = bha.ba_feature; - LIST_INSERT_HEAD(&sc->sc_list, hidev, sc_next); - } - } - - /* - * start bluetooth connections - */ - mutex_enter(&bt_lock); - if ((sc->sc_flags & BTHID_RECONNECT) == 0) - bthidev_listen(sc); - - if (sc->sc_flags & BTHID_CONNECTING) - bthidev_connect(sc); - mutex_exit(&bt_lock); -} - -int -bthidev_detach(struct device *self, int flags) -{ - struct bthidev_softc *sc = (struct bthidev_softc *)self; - struct bthidev *hidev; - - mutex_enter(&bt_lock); - sc->sc_flags = 0; /* disable reconnecting */ - - /* release interrupt listen */ - if (sc->sc_int_l != NULL) { - l2cap_detach(&sc->sc_int_l); - sc->sc_int_l = NULL; - } - - /* release control listen */ - if (sc->sc_ctl_l != NULL) { - l2cap_detach(&sc->sc_ctl_l); - sc->sc_ctl_l = NULL; - } - - /* close interrupt channel */ - if (sc->sc_int != NULL) { - l2cap_disconnect(sc->sc_int, 0); - l2cap_detach(&sc->sc_int); - sc->sc_int = NULL; - } - - /* close control channel */ - if (sc->sc_ctl != NULL) { - l2cap_disconnect(sc->sc_ctl, 0); - l2cap_detach(&sc->sc_ctl); - sc->sc_ctl = NULL; - } - - /* remove timeout */ - timeout_del(&sc->sc_reconnect); - - mutex_exit(&bt_lock); - - /* detach children */ - while ((hidev = LIST_FIRST(&sc->sc_list)) != NULL) { - LIST_REMOVE(hidev, sc_next); - config_detach(&hidev->sc_dev, flags); - } - - /* release descriptor */ - if (sc->sc_desc != NULL) { - free(sc->sc_desc, M_BTHIDEV); - sc->sc_desc = NULL; - } - return 0; -} - -/* - * bthidev config print - */ -int -bthidev_print(void *aux, const char *pnp) -{ - struct bthidev_attach_args *ba = aux; - - if (pnp != NULL) - printf("%s:", pnp); - - if (ba->ba_id > 0) - printf(" reportid %d", ba->ba_id); - - return UNCONF; -} - -int -bthidevsubmatch(struct device *parent, void *match, void *aux) -{ - struct bthidev_attach_args *ba = aux; - struct cfdata *cf = match; - - if (cf->bthidevcf_reportid != BTHIDEV_UNK_REPORTID && - cf->bthidevcf_reportid != ba->ba_id) - return (0); - - return ((*cf->cf_attach->ca_match)(parent, cf, aux)); -} - - -/***************************************************************************** - * - * bluetooth(4) HID attach/detach routines - */ - -/* - * callouts are scheduled after connections have been lost, in order - * to clean up and reconnect. - */ -void -bthidev_timeout(void *arg) -{ - struct bthidev_softc *sc = arg; - - mutex_enter(&bt_lock); - - switch (sc->sc_state) { - case BTHID_CLOSED: - if (sc->sc_int != NULL) { - l2cap_disconnect(sc->sc_int, 0); - break; - } - - if (sc->sc_ctl != NULL) { - l2cap_disconnect(sc->sc_ctl, 0); - break; - } - - if (sc->sc_flags & BTHID_RECONNECT) { - sc->sc_flags |= BTHID_CONNECTING; - bthidev_connect(sc); - break; - } - - break; - - case BTHID_WAIT_CTL: - break; - - case BTHID_WAIT_INT: - break; - - case BTHID_OPEN: - break; - - default: - break; - } - mutex_exit(&bt_lock); -} - -/* - * listen for our device - */ -int -bthidev_listen(struct bthidev_softc *sc) -{ - struct sockaddr_bt sa; - int err; - - memset(&sa, 0, sizeof(sa)); - sa.bt_len = sizeof(sa); - sa.bt_family = AF_BLUETOOTH; - bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); - - /* - * Listen on control PSM - */ - err = l2cap_attach(&sc->sc_ctl_l, &bthidev_ctl_proto, sc); - if (err) - return err; - - err = l2cap_setlinkmode(sc->sc_ctl_l, sc->sc_mode); - if (err) - return err; - - sa.bt_psm = sc->sc_ctlpsm; - err = l2cap_bind(sc->sc_ctl_l, &sa); - if (err) - return err; - - err = l2cap_listen(sc->sc_ctl_l); - if (err) - return err; - - /* - * Listen on interrupt PSM - */ - err = l2cap_attach(&sc->sc_int_l, &bthidev_int_proto, sc); - if (err) - return err; - - err = l2cap_setlinkmode(sc->sc_int_l, sc->sc_mode); - if (err) - return err; - - sa.bt_psm = sc->sc_intpsm; - err = l2cap_bind(sc->sc_int_l, &sa); - if (err) - return err; - - err = l2cap_listen(sc->sc_int_l); - if (err) - return err; - - sc->sc_state = BTHID_WAIT_CTL; - return 0; -} - -/* - * start connecting to our device - */ -int -bthidev_connect(struct bthidev_softc *sc) -{ - struct sockaddr_bt sa; - int err; - - if (sc->sc_attempts++ > 0) - printf("%s: connect (#%d)\n", - sc->sc_btdev.sc_dev.dv_xname, sc->sc_attempts); - - memset(&sa, 0, sizeof(sa)); - sa.bt_len = sizeof(sa); - sa.bt_family = AF_BLUETOOTH; - - err = l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc); - if (err) { - printf("%s: l2cap_attach failed (%d)\n", - sc->sc_btdev.sc_dev.dv_xname, err); - return err; - } - - err = l2cap_setlinkmode(sc->sc_ctl, sc->sc_mode); - if (err) - return err; - - bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); - err = l2cap_bind(sc->sc_ctl, &sa); - if (err) { - printf("%s: l2cap_bind failed (%d)\n", - sc->sc_btdev.sc_dev.dv_xname, err); - return err; - } - - sa.bt_psm = sc->sc_ctlpsm; - bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); - err = l2cap_connect(sc->sc_ctl, &sa); - if (err) { - printf("%s: l2cap_connect failed (%d)\n", - sc->sc_btdev.sc_dev.dv_xname, err); - return err; - } - - sc->sc_state = BTHID_WAIT_CTL; - return 0; -} - -/***************************************************************************** - * - * bluetooth(9) callback methods for L2CAP - * - * All these are called from Bluetooth Protocol code, in a soft - * interrupt context at IPL_SOFTNET. - */ - -void -bthidev_connecting(void *arg) -{ - /* don't care */ -} - -void -bthidev_ctl_connected(void *arg) -{ - struct sockaddr_bt sa; - struct bthidev_softc *sc = arg; - int err; - - if (sc->sc_state != BTHID_WAIT_CTL) - return; - - KASSERT(sc->sc_ctl != NULL); - KASSERT(sc->sc_int == NULL); - - if (sc->sc_flags & BTHID_CONNECTING) { - /* initiate connect on interrupt PSM */ - err = l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc); - if (err) - goto fail; - - err = l2cap_setlinkmode(sc->sc_int, sc->sc_mode); - if (err) - goto fail; - - memset(&sa, 0, sizeof(sa)); - sa.bt_len = sizeof(sa); - sa.bt_family = AF_BLUETOOTH; - bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); - - err = l2cap_bind(sc->sc_int, &sa); - if (err) - goto fail; - - sa.bt_psm = sc->sc_intpsm; - bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); - err = l2cap_connect(sc->sc_int, &sa); - if (err) - goto fail; - } - - sc->sc_state = BTHID_WAIT_INT; - return; - -fail: - l2cap_detach(&sc->sc_ctl); - sc->sc_ctl = NULL; - printf("%s: connect failed (%d)\n", - sc->sc_btdev.sc_dev.dv_xname, err); -} - -void -bthidev_int_connected(void *arg) -{ - struct bthidev_softc *sc = arg; - - if (sc->sc_state != BTHID_WAIT_INT) - return; - - KASSERT(sc->sc_ctl != NULL); - KASSERT(sc->sc_int != NULL); - - sc->sc_attempts = 0; - sc->sc_flags &= ~BTHID_CONNECTING; - sc->sc_state = BTHID_OPEN; - - printf("%s: connected\n", sc->sc_btdev.sc_dev.dv_xname); -} - -/* - * Disconnected - * - * Depending on our state, this could mean several things, but essentially - * we are lost. If both channels are closed, and we are marked to reconnect, - * schedule another try otherwise just give up. They will contact us. - */ -void -bthidev_ctl_disconnected(void *arg, int err) -{ - struct bthidev_softc *sc = arg; - - if (sc->sc_ctl != NULL) { - l2cap_detach(&sc->sc_ctl); - sc->sc_ctl = NULL; - } - - sc->sc_state = BTHID_CLOSED; - - if (sc->sc_int == NULL) { - printf("%s: disconnected\n", sc->sc_btdev.sc_dev.dv_xname); - sc->sc_flags &= ~BTHID_CONNECTING; - - if (sc->sc_flags & BTHID_RECONNECT) - timeout_add_sec(&sc->sc_reconnect, - BTHID_RETRY_INTERVAL); - else - sc->sc_state = BTHID_WAIT_CTL; - } else { - /* - * The interrupt channel should have been closed first, - * but its potentially unsafe to detach that from here. - * Give them a second to do the right thing or let the - * callout handle it. - */ - timeout_add_sec(&sc->sc_reconnect, 1); - } -} - -void -bthidev_int_disconnected(void *arg, int err) -{ - struct bthidev_softc *sc = arg; - - if (sc->sc_int != NULL) { - l2cap_detach(&sc->sc_int); - sc->sc_int = NULL; - } - - sc->sc_state = BTHID_CLOSED; - - if (sc->sc_ctl == NULL) { - printf("%s: disconnected\n", sc->sc_btdev.sc_dev.dv_xname); - sc->sc_flags &= ~BTHID_CONNECTING; - - if (sc->sc_flags & BTHID_RECONNECT) - timeout_add_sec(&sc->sc_reconnect, - BTHID_RETRY_INTERVAL); - else - sc->sc_state = BTHID_WAIT_CTL; - } else { - /* - * The control channel should be closing also, allow - * them a chance to do that before we force it. - */ - timeout_add_sec(&sc->sc_reconnect, 1); - } -} - -/* - * New Connections - * - * We give a new L2CAP handle back if this matches the BDADDR we are - * listening for and we are in the right state. bthidev_connected will - * be called when the connection is open, so nothing else to do here - */ -void * -bthidev_ctl_newconn(void *arg, struct sockaddr_bt *laddr, - struct sockaddr_bt *raddr) -{ - struct bthidev_softc *sc = arg; - - if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0 - || (sc->sc_flags & BTHID_CONNECTING) - || sc->sc_state != BTHID_WAIT_CTL - || sc->sc_ctl != NULL - || sc->sc_int != NULL) - return NULL; - - l2cap_attach(&sc->sc_ctl, &bthidev_ctl_proto, sc); - return sc->sc_ctl; -} - -void * -bthidev_int_newconn(void *arg, struct sockaddr_bt *laddr, - struct sockaddr_bt *raddr) -{ - struct bthidev_softc *sc = arg; - - if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0 - || (sc->sc_flags & BTHID_CONNECTING) - || sc->sc_state != BTHID_WAIT_INT - || sc->sc_ctl == NULL - || sc->sc_int != NULL) - return NULL; - - l2cap_attach(&sc->sc_int, &bthidev_int_proto, sc); - return sc->sc_int; -} - -void -bthidev_complete(void *arg, int count) -{ - - /* dont care */ -} - -void -bthidev_linkmode(void *arg, int new) -{ - struct bthidev_softc *sc = arg; - - if ((sc->sc_mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH)) - printf("%s: auth failed\n", sc->sc_btdev.sc_dev.dv_xname); - else if ((sc->sc_mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT)) - printf("%s: encrypt off\n", sc->sc_btdev.sc_dev.dv_xname); - else if ((sc->sc_mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)) - printf("%s: insecure\n", sc->sc_btdev.sc_dev.dv_xname); - else - return; - - if (sc->sc_int != NULL) - l2cap_disconnect(sc->sc_int, 0); - - if (sc->sc_ctl != NULL) - l2cap_disconnect(sc->sc_ctl, 0); -} - -/* - * Receive reports from the protocol stack. - */ -void -bthidev_input(void *arg, struct mbuf *m) -{ - struct bthidev_softc *sc = arg; - struct bthidev *hidev; - uint8_t *data; - int len; - - if (sc->sc_state != BTHID_OPEN) - goto release; - - if (m->m_pkthdr.len > m->m_len) - printf("%s: truncating HID report\n", - sc->sc_btdev.sc_dev.dv_xname); - - len = m->m_len; - data = mtod(m, uint8_t *); - - if (BTHID_TYPE(data[0]) == BTHID_DATA) { - /* - * data[0] == type / parameter - * data[1] == id - * data[2..len] == report - */ - if (len < 3) - goto release; - - LIST_FOREACH(hidev, &sc->sc_list, sc_next) { - if (data[1] == hidev->sc_id) { - switch (BTHID_DATA_PARAM(data[0])) { - case BTHID_DATA_INPUT: - (*hidev->sc_input)(hidev, data + 2, len - 2); - break; - - case BTHID_DATA_FEATURE: - (*hidev->sc_feature)(hidev, data + 2, len - 2); - break; - - default: - break; - } - - goto release; - } - } - printf("%s: report id %d, len = %d ignored\n", - sc->sc_btdev.sc_dev.dv_xname, data[1], len - 2); - - goto release; - } - - if (BTHID_TYPE(data[0]) == BTHID_CONTROL) { - if (len < 1) - goto release; - - if (BTHID_DATA_PARAM(data[0]) == BTHID_CONTROL_UNPLUG) { - printf("%s: unplugged\n", - sc->sc_btdev.sc_dev.dv_xname); - - /* close interrupt channel */ - if (sc->sc_int != NULL) { - l2cap_disconnect(sc->sc_int, 0); - l2cap_detach(&sc->sc_int); - sc->sc_int = NULL; - } - - /* close control channel */ - if (sc->sc_ctl != NULL) { - l2cap_disconnect(sc->sc_ctl, 0); - l2cap_detach(&sc->sc_ctl); - sc->sc_ctl = NULL; - } - } - - goto release; - } - -release: - m_freem(m); -} - -/***************************************************************************** - * - * IO routines - */ - -void -bthidev_null(struct bthidev *hidev, uint8_t *report, int len) -{ - - /* - * empty routine just in case the device - * provided no method to handle this report - */ -} - -int -bthidev_output(struct bthidev *hidev, uint8_t *report, int rlen, int nolock) -{ - struct bthidev_softc *sc = (struct bthidev_softc *)hidev->sc_parent; - struct mbuf *m; - int err; - - if (sc == NULL || sc->sc_state != BTHID_OPEN) - return ENOTCONN; - - KASSERT(sc->sc_ctl != NULL); - KASSERT(sc->sc_int != NULL); - - if (rlen == 0 || report == NULL) - return 0; - - if (rlen > MHLEN - 2) { - printf("%s: output report too long (%d)!\n", - sc->sc_btdev.sc_dev.dv_xname, rlen); - - return EMSGSIZE; - } - - m = m_gethdr(M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - - /* - * data[0] = type / parameter - * data[1] = id - * data[2..N] = report - */ - mtod(m, uint8_t *)[0] = (uint8_t)((BTHID_DATA << 4) | BTHID_DATA_OUTPUT); - mtod(m, uint8_t *)[1] = hidev->sc_id; - memcpy(mtod(m, uint8_t *) + 2, report, rlen); - m->m_pkthdr.len = m->m_len = rlen + 2; - - if (!nolock) - mutex_enter(&bt_lock); - err = l2cap_send(sc->sc_int, m); - if (!nolock) - mutex_exit(&bt_lock); - - return err; -} diff --git a/sys/dev/bluetooth/bthidev.h b/sys/dev/bluetooth/bthidev.h deleted file mode 100644 index 2932d02d5c9..00000000000 --- a/sys/dev/bluetooth/bthidev.h +++ /dev/null @@ -1,79 +0,0 @@ -/* $OpenBSD: bthidev.h,v 1.4 2010/08/05 13:13:17 miod Exp $ */ -/* $NetBSD: bthidev.h,v 1.4 2007/11/03 17:41:03 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _DEV_BLUETOOTH_BTHIDEV_H_ -#define _DEV_BLUETOOTH_BTHIDEV_H_ - -#ifdef _KERNEL - -#define BTHIDBUSCF_REPORTID 0 -#define BTHIDBUSCF_REPORTID_DEFAULT -1 - -#define bthidevcf_reportid cf_loc[BTHIDBUSCF_REPORTID] -#define BTHIDEV_UNK_REPORTID BTHIDBUSCF_REPORTID_DEFAULT - -/* HID device header */ -struct bthidev { - struct device sc_dev; - struct btdev *sc_parent; - - int sc_id; /* report id */ - int sc_len; /* report len */ - - void (*sc_input) /* input method */ - (struct bthidev *, uint8_t *, int); - - void (*sc_feature) /* feature method */ - (struct bthidev *, uint8_t *, int); - - LIST_ENTRY(bthidev) sc_next; -}; - -/* HID device attach arguments */ -struct bthidev_attach_args { - void *ba_desc; /* descriptor */ - int ba_dlen; /* descriptor length */ - int ba_id; /* report id */ - - void (*ba_input) /* input method */ - (struct bthidev *, uint8_t *, int); - void (*ba_feature) /* feature method */ - (struct bthidev *, uint8_t *, int); - int (*ba_output) /* output method */ - (struct bthidev *, uint8_t *, int, int); -}; - -#endif /* _KERNEL */ - -#endif /* _DEV_BLUETOOTH_BTHIDEV_H_ */ diff --git a/sys/dev/bluetooth/bthub.c b/sys/dev/bluetooth/bthub.c deleted file mode 100644 index 3780fff2382..00000000000 --- a/sys/dev/bluetooth/bthub.c +++ /dev/null @@ -1,241 +0,0 @@ -/* $OpenBSD: bthub.c,v 1.6 2013/12/15 14:32:38 pirofti Exp $ */ - -/* - * Copyright (c) 2007 Uwe Stuehler <uwe@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/device.h> -#include <sys/ioctl.h> -#include <sys/fcntl.h> -#include <sys/vnode.h> - -#include <netbt/bluetooth.h> - -#include <dev/bluetooth/btdev.h> - -struct bthub_softc { - struct device sc_dev; - int sc_open; - bdaddr_t sc_laddr; - LIST_HEAD(, btdev) sc_list; -}; - -int bthub_match(struct device *, void *, void *); -void bthub_attach(struct device *, struct device *, void *); -int bthub_detach(struct device *, int); -int bthub_print(void *, const char *); -int bthub_devioctl(dev_t, u_long, struct btdev_attach_args *); -int bthubopen(dev_t, int, int, struct proc *); -int bthubclose(dev_t, int, int, struct proc *); -int bthubioctl(dev_t, u_long, caddr_t, int, struct proc *); - -struct cfattach bthub_ca = { - sizeof(struct bthub_softc), bthub_match, bthub_attach, bthub_detach -}; - -struct cfdriver bthub_cd = { - NULL, "bthub", DV_DULL -}; - -int -bthub_match(struct device *parent, void *match, void *aux) -{ - return (1); -} - -void -bthub_attach(struct device *parent, struct device *self, void *aux) -{ - struct bthub_softc *sc = (struct bthub_softc *)self; - bdaddr_t *addr = aux; - - sc->sc_open = 0; - bdaddr_copy(&sc->sc_laddr, addr); - - printf(" %02x:%02x:%02x:%02x:%02x:%02x\n", - addr->b[5], addr->b[4], addr->b[3], - addr->b[2], addr->b[1], addr->b[0]); -} - -int -bthub_detach(struct device *self, int flags) -{ - struct bthub_softc *sc = (struct bthub_softc *)self; - struct btdev *btdev; - int maj, mn; - int err; - - /* Locate the major number */ - for (maj = 0; maj < nchrdev; maj++) - if (cdevsw[maj].d_open == bthubopen) - break; - - /* Nuke the vnodes for any open instances (calls close) */ - mn = self->dv_unit; - vdevgone(maj, mn, mn, VCHR); - - /* Detach all child devices. */ - while (!LIST_EMPTY(&sc->sc_list)) { - btdev = LIST_FIRST(&sc->sc_list); - LIST_REMOVE(btdev, sc_next); - - err = config_detach(&btdev->sc_dev, flags); - if (err && (flags & DETACH_FORCE) == 0) { - LIST_INSERT_HEAD(&sc->sc_list, btdev, sc_next); - return err; - } - } - - return (0); -} - -int -bthub_print(void *aux, const char *parentname) -{ - struct btdev_attach_args *bd = aux; - bdaddr_t *raddr = &bd->bd_raddr; - - if (parentname != NULL) - return QUIET; - - printf(" %02x:%02x:%02x:%02x:%02x:%02x", - raddr->b[5], raddr->b[4], raddr->b[3], raddr->b[2], - raddr->b[1], raddr->b[0]); - return QUIET; -} - -int -bthubopen(dev_t dev, int flag, int mode, struct proc *p) -{ - struct device *dv; - struct bthub_softc *sc; - - dv = device_lookup(&bthub_cd, minor(dev)); - if (dv == NULL) - return (ENXIO); - - sc = (struct bthub_softc *)dv; - if (sc->sc_open) { - device_unref(dv); - return (EBUSY); - } - - sc->sc_open = 1; - device_unref(dv); - - return (0); -} - -int -bthubclose(dev_t dev, int flag, int mode, struct proc *p) -{ - struct device *dv; - struct bthub_softc *sc; - - dv = device_lookup(&bthub_cd, minor(dev)); - sc = (struct bthub_softc *)dv; - sc->sc_open = 0; - device_unref(dv); - - return (0); -} - -int -bthubioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) -{ - struct btdev_attach_args *bd; - int err; - - switch (cmd) { - case BTDEV_ATTACH: - case BTDEV_DETACH: - if ((flag & FWRITE) == 0) - return (EACCES); - default: - break; - } - - switch (cmd) { - case BTDEV_ATTACH: - case BTDEV_DETACH: - bd = (struct btdev_attach_args *)data; - err = bthub_devioctl(dev, cmd, bd); - break; - default: - err = ENOTTY; - } - - return err; -} - -int -bthub_devioctl(dev_t dev, u_long cmd, struct btdev_attach_args *bd) -{ - struct device *dv; - struct bthub_softc *sc; - struct btdev *btdev; - int unit; - - /* Locate the relevant bthub. */ - for (unit = 0; unit < bthub_cd.cd_ndevs; unit++) { - if ((dv = bthub_cd.cd_devs[unit]) == NULL) - continue; - - sc = (struct bthub_softc *)dv; - if (bdaddr_same(&sc->sc_laddr, &bd->bd_laddr)) - break; - } - if (unit == bthub_cd.cd_ndevs) - return (ENXIO); - - /* Locate matching child device, if any. */ - LIST_FOREACH(btdev, &sc->sc_list, sc_next) { - if (!bdaddr_same(&btdev->sc_addr, &bd->bd_raddr)) - continue; - if (btdev->sc_type != bd->bd_type) - continue; - break; - } - - switch (cmd) { - case BTDEV_ATTACH: - if (btdev != NULL) - return EADDRINUSE; - - dv = config_found(&sc->sc_dev, bd, bthub_print); - if (dv == NULL) - return ENXIO; - - btdev = (struct btdev *)dv; - bdaddr_copy(&btdev->sc_addr, &bd->bd_raddr); - btdev->sc_type = bd->bd_type; - LIST_INSERT_HEAD(&sc->sc_list, btdev, sc_next); - break; - - case BTDEV_DETACH: - if (btdev == NULL) - return ENXIO; - - LIST_REMOVE(btdev, sc_next); - config_detach(&btdev->sc_dev, DETACH_FORCE); - break; - } - - return 0; -} - diff --git a/sys/dev/bluetooth/btkbd.c b/sys/dev/bluetooth/btkbd.c deleted file mode 100644 index 5de8553c04a..00000000000 --- a/sys/dev/bluetooth/btkbd.c +++ /dev/null @@ -1,225 +0,0 @@ -/* $OpenBSD: btkbd.c,v 1.7 2010/08/05 13:13:17 miod Exp $ */ -/* $NetBSD: btkbd.c,v 1.10 2008/09/09 03:54:56 cube Exp $ */ - -/* - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (lennart@augustsson.net) at - * Carlstedt Research & Technology. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/conf.h> -#include <sys/device.h> -#include <sys/kernel.h> -#include <sys/proc.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> - -#include <dev/bluetooth/bthid.h> -#include <dev/bluetooth/bthidev.h> - -#include <dev/usb/hid.h> -#include <dev/usb/usb.h> -#include <dev/usb/usbhid.h> - -#include <dev/wscons/wsconsio.h> -#include <dev/wscons/wskbdvar.h> -#include <dev/wscons/wsksymdef.h> -#include <dev/wscons/wsksymvar.h> - -#include <dev/usb/hidkbdsc.h> -#include <dev/usb/hidkbdvar.h> - -struct btkbd_softc { - struct bthidev sc_hidev; /* device */ - struct hidkbd sc_kbd; /* keyboard state */ - int (*sc_output) /* output method */ - (struct bthidev *, uint8_t *, int, int); - int sc_inintr; -}; - -/* autoconf(9) methods */ -int btkbd_match(struct device *, void *, void *); -void btkbd_attach(struct device *, struct device *, void *); -int btkbd_detach(struct device *, int); - -struct cfdriver btkbd_cd = { - NULL, "btkbd", DV_DULL -}; - -const struct cfattach btkbd_ca = { - sizeof(struct btkbd_softc), - btkbd_match, - btkbd_attach, - btkbd_detach, - /* XXX activate */ -}; - -/* wskbd(4) accessops */ -int btkbd_enable(void *, int); -void btkbd_set_leds(void *, int); -int btkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); - -const struct wskbd_accessops btkbd_accessops = { - btkbd_enable, - btkbd_set_leds, - btkbd_ioctl -}; - -/* bthid methods */ -void btkbd_input(struct bthidev *, uint8_t *, int); - -int -btkbd_match(struct device *self, void *match, void *aux) -{ - struct bthidev_attach_args *ba = aux; - - if (hid_is_collection(ba->ba_desc, ba->ba_dlen, ba->ba_id, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) - return 1; - - return 0; -} - -void -btkbd_attach(struct device *parent, struct device *self, void *aux) -{ - struct btkbd_softc *sc = (struct btkbd_softc *)self; - struct hidkbd *kbd = &sc->sc_kbd; - struct bthidev_attach_args *ba = aux; - kbd_t layout; - - sc->sc_output = ba->ba_output; - ba->ba_input = btkbd_input; /* XXX ugly */ - - if (hidkbd_attach(self, kbd, 0, 0, - ba->ba_id, ba->ba_desc, ba->ba_dlen) != 0) - return; - - printf("\n"); - -#if defined(BTKBD_LAYOUT) - layout = BTKBD_LAYOUT; -#else - layout = KB_US; -#endif - hidkbd_attach_wskbd(kbd, layout, &btkbd_accessops); -} - -int -btkbd_detach(struct device *self, int flags) -{ - struct btkbd_softc *sc = (struct btkbd_softc *)self; - - return hidkbd_detach(&sc->sc_kbd, flags); -} - -int -btkbd_enable(void *self, int on) -{ - struct btkbd_softc *sc = (struct btkbd_softc *)self; - struct hidkbd *kbd = &sc->sc_kbd; - - return hidkbd_enable(kbd, on); -} - -void -btkbd_set_leds(void *self, int leds) -{ - struct btkbd_softc *sc = (struct btkbd_softc *)self; - struct hidkbd *kbd = &sc->sc_kbd; - uint8_t report; - - if (hidkbd_set_leds(kbd, leds, &report) != 0) { - if (sc->sc_output != NULL) - (*sc->sc_output)(&sc->sc_hidev, &report, - sizeof(report), sc->sc_inintr); - } -} - -int -btkbd_ioctl(void *self, u_long cmd, caddr_t data, int flag, struct proc *p) -{ - struct btkbd_softc *sc = (struct btkbd_softc *)self; - struct hidkbd *kbd = &sc->sc_kbd; - - switch (cmd) { - case WSKBDIO_GTYPE: - *(int *)data = WSKBD_TYPE_BLUETOOTH; - return 0; - case WSKBDIO_SETLEDS: - btkbd_set_leds(sc, *(int *)data); - return 0; - default: - return hidkbd_ioctl(kbd, cmd, data, flag, p); - } -} - -void -btkbd_input(struct bthidev *self, uint8_t *data, int len) -{ - struct btkbd_softc *sc = (struct btkbd_softc *)self; - struct hidkbd *kbd = &sc->sc_kbd; - - if (kbd->sc_enabled != 0) { - sc->sc_inintr = 1; - hidkbd_input(kbd, data, len); - sc->sc_inintr = 0; - } -} diff --git a/sys/dev/bluetooth/btms.c b/sys/dev/bluetooth/btms.c deleted file mode 100644 index 2c188a40330..00000000000 --- a/sys/dev/bluetooth/btms.c +++ /dev/null @@ -1,205 +0,0 @@ -/* $OpenBSD: btms.c,v 1.6 2011/03/04 23:57:52 kettenis Exp $ */ -/* $NetBSD: btms.c,v 1.8 2008/09/09 03:54:56 cube Exp $ */ - -/* - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (lennart@augustsson.net) at - * Carlstedt Research & Technology. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/conf.h> -#include <sys/device.h> -#include <sys/proc.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> - -#include <dev/bluetooth/bthid.h> -#include <dev/bluetooth/bthidev.h> - -#include <dev/usb/hid.h> -#include <dev/usb/usb.h> -#include <dev/usb/usbhid.h> - -#include <dev/wscons/wsconsio.h> -#include <dev/wscons/wsmousevar.h> - -#include <dev/usb/hidmsvar.h> - -struct btms_softc { - struct bthidev sc_hidev; - struct hidms sc_ms; -}; - -/* autoconf(9) methods */ -int btms_match(struct device *, void *, void *); -void btms_attach(struct device *, struct device *, void *); -int btms_detach(struct device *, int); - -struct cfdriver btms_cd = { - NULL, "btms", DV_DULL -}; - -const struct cfattach btms_ca = { - sizeof(struct btms_softc), - btms_match, - btms_attach, - btms_detach, - /* XXX activate */ -}; - -/* wsmouse(4) accessops */ -int btms_wsmouse_enable(void *); -int btms_wsmouse_ioctl(void *, u_long, caddr_t, int, struct proc *); -void btms_wsmouse_disable(void *); - -const struct wsmouse_accessops btms_wsmouse_accessops = { - btms_wsmouse_enable, - btms_wsmouse_ioctl, - btms_wsmouse_disable, -}; - -/* bthid methods */ -void btms_input(struct bthidev *, uint8_t *, int); - - -int -btms_match(struct device *parent, void *match, void *aux) -{ - struct bthidev_attach_args *ba = aux; - - if (hid_is_collection(ba->ba_desc, ba->ba_dlen, ba->ba_id, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) - return 1; - - return 0; -} - -void -btms_attach(struct device *parent, struct device *self, void *aux) -{ - struct btms_softc *sc = (struct btms_softc *)self; - struct hidms *ms = &sc->sc_ms; - struct bthidev_attach_args *ba = aux; - - ba->ba_input = btms_input; /* XXX ugly */ - - if (hidms_setup(self, ms, 0, ba->ba_id, ba->ba_desc, ba->ba_dlen) != 0) - return; - - hidms_attach(ms, &btms_wsmouse_accessops); -} - -int -btms_detach(struct device *self, int flags) -{ - struct btms_softc *sc = (struct btms_softc *)self; - struct hidms *ms = &sc->sc_ms; - - return hidms_detach(ms, flags); -} - -int -btms_wsmouse_enable(void *self) -{ - struct btms_softc *sc = (struct btms_softc *)self; - struct hidms *ms = &sc->sc_ms; - - return hidms_enable(ms); -} - -int -btms_wsmouse_ioctl(void *self, u_long cmd, caddr_t data, int flag, - struct proc *p) -{ - struct btms_softc *sc = (struct btms_softc *)self; - struct hidms *ms = &sc->sc_ms; - int rc; - - rc = hidms_ioctl(ms, cmd, data, flag, p); - if (rc != -1) - return rc; - - switch (cmd) { - case WSMOUSEIO_GTYPE: - *(u_int *)data = WSMOUSE_TYPE_BLUETOOTH; - return 0; - default: - return -1; - } -} - -void -btms_wsmouse_disable(void *self) -{ - struct btms_softc *sc = (struct btms_softc *)self; - struct hidms *ms = &sc->sc_ms; - - hidms_disable(ms); -} - -void -btms_input(struct bthidev *self, uint8_t *data, int len) -{ - struct btms_softc *sc = (struct btms_softc *)self; - struct hidms *ms = &sc->sc_ms; - - if (ms->sc_enabled != 0) - hidms_input(ms, data, len); -} diff --git a/sys/dev/bluetooth/btsco.c b/sys/dev/bluetooth/btsco.c deleted file mode 100644 index 6e8beb39957..00000000000 --- a/sys/dev/bluetooth/btsco.c +++ /dev/null @@ -1,1224 +0,0 @@ -/* $OpenBSD: btsco.c,v 1.6 2013/05/15 08:29:24 ratchov Exp $ */ -/* $NetBSD: btsco.c,v 1.22 2008/08/06 15:01:23 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/audioio.h> -#include <sys/conf.h> -#include <sys/device.h> -#include <sys/fcntl.h> -#include <sys/ioctl.h> -#include <sys/kernel.h> -#include <sys/queue.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/socketvar.h> -#include <sys/systm.h> -#include <sys/timeout.h> - -#include <netbt/bluetooth.h> -#include <netbt/rfcomm.h> -#include <netbt/sco.h> - -#include <dev/audio_if.h> -#include <dev/auconv.h> -#include <dev/mulaw.h> - -#include <dev/bluetooth/btdev.h> -#include <dev/bluetooth/btsco.h> - -typedef struct audio_params audio_params_t; - -struct audio_format { - void *driver_data; - int32_t mode; - u_int encoding; - u_int validbits; - u_int precision; - u_int channels; - u_int channel_mask; -#define AUFMT_UNKNOWN_POSITION 0U -#define AUFMT_FRONT_LEFT 0x00001U /* USB audio compatible */ -#define AUFMT_FRONT_RIGHT 0x00002U /* USB audio compatible */ -#define AUFMT_FRONT_CENTER 0x00004U /* USB audio compatible */ -#define AUFMT_LOW_FREQUENCY 0x00008U /* USB audio compatible */ -#define AUFMT_BACK_LEFT 0x00010U /* USB audio compatible */ -#define AUFMT_BACK_RIGHT 0x00020U /* USB audio compatible */ -#define AUFMT_FRONT_LEFT_OF_CENTER 0x00040U /* USB audio compatible */ -#define AUFMT_FRONT_RIGHT_OF_CENTER 0x00080U /* USB audio compatible */ -#define AUFMT_BACK_CENTER 0x00100U /* USB audio compatible */ -#define AUFMT_SIDE_LEFT 0x00200U /* USB audio compatible */ -#define AUFMT_SIDE_RIGHT 0x00400U /* USB audio compatible */ -#define AUFMT_TOP_CENTER 0x00800U /* USB audio compatible */ -#define AUFMT_TOP_FRONT_LEFT 0x01000U -#define AUFMT_TOP_FRONT_CENTER 0x02000U -#define AUFMT_TOP_FRONT_RIGHT 0x04000U -#define AUFMT_TOP_BACK_LEFT 0x08000U -#define AUFMT_TOP_BACK_CENTER 0x10000U -#define AUFMT_TOP_BACK_RIGHT 0x20000U - -#define AUFMT_MONAURAL AUFMT_FRONT_CENTER -#define AUFMT_STEREO (AUFMT_FRONT_LEFT | AUFMT_FRONT_RIGHT) -#define AUFMT_SURROUND4 (AUFMT_STEREO | AUFMT_BACK_LEFT \ - | AUFMT_BACK_RIGHT) -#define AUFMT_DOLBY_5_1 (AUFMT_SURROUND4 | AUFMT_FRONT_CENTER \ - | AUFMT_LOW_FREQUENCY) - - /** - * 0: frequency[0] is lower limit, and frequency[1] is higher limit. - * 1-16: frequency[0] to frequency[frequency_type-1] are valid. - */ - u_int frequency_type; - -#define AUFMT_MAX_FREQUENCIES 16 - /** - * sampling rates - */ - u_int frequency[AUFMT_MAX_FREQUENCIES]; -}; - -#undef DPRINTF -#undef DPRINTFN - -#ifdef BTSCO_DEBUG -int btsco_debug = BTSCO_DEBUG; -#define DPRINTF(fmt, args...) do { \ - if (btsco_debug) \ - printf("%s: "fmt, __func__ , ##args); \ -} while (/* CONSTCOND */0) - -#define DPRINTFN(n, fmt, args...) do { \ - if (btsco_debug > (n)) \ - printf("%s: "fmt, __func__ , ##args); \ -} while (/* CONSTCOND */0) -#else -#define DPRINTF(...) -#define DPRINTFN(...) -#endif - -/***************************************************************************** - * - * Bluetooth SCO Audio device - */ - -/* btsco softc */ -struct btsco_softc { - struct device sc_dev; - struct device *sc_audio; /* MI audio device */ - uint16_t sc_flags; - const char *sc_name; /* our device_xname */ - - void *sc_intr; /* interrupt cookie */ - struct timeout sc_intr_to; /* interrupt trigger */ - int sc_connect; /* connect wait */ - - /* Bluetooth */ - bdaddr_t sc_laddr; /* local address */ - bdaddr_t sc_raddr; /* remote address */ - uint16_t sc_state; /* link state */ - struct sco_pcb *sc_sco; /* SCO handle */ - struct sco_pcb *sc_sco_l; /* SCO listen handle */ - uint16_t sc_mtu; /* SCO mtu */ - uint8_t sc_channel; /* RFCOMM channel */ - int sc_err; /* stored error */ - - /* Receive */ - int sc_rx_want; /* bytes wanted */ - uint8_t *sc_rx_block; /* receive block */ - void (*sc_rx_intr)(void *); /* callback */ - void *sc_rx_intrarg; /* callback arg */ - struct mbuf *sc_rx_mbuf; /* leftover mbuf */ - - /* Transmit */ - int sc_tx_size; /* bytes to send */ - int sc_tx_pending; /* packets pending */ - uint8_t *sc_tx_block; /* transmit block */ - void (*sc_tx_intr)(void *); /* callback */ - void *sc_tx_intrarg; /* callback arg */ - void *sc_tx_buf; /* transmit buffer */ - int sc_tx_refcnt; /* buffer refcnt */ - - /* mixer data */ - int sc_vgs; /* speaker volume */ - int sc_vgm; /* mic volume */ -}; - -/* sc_state */ -#define BTSCO_CLOSED 0 -#define BTSCO_WAIT_CONNECT 1 -#define BTSCO_OPEN 2 - -/* sc_flags */ -#define BTSCO_LISTEN (1 << 1) - -/* autoconf(9) glue */ -int btsco_match(struct device *, void *, void *); -void btsco_attach(struct device *, struct device *, void *); -int btsco_detach(struct device *, int); - -struct cfattach btsco_ca = { - sizeof(struct btsco_softc), - btsco_match, - btsco_attach, - btsco_detach -}; - -struct cfdriver btsco_cd = { - NULL, "btsco", DV_DULL -}; - -/* audio(9) glue */ -static int btsco_open(void *, int); -static void btsco_close(void *); -static int btsco_query_encoding(void *, struct audio_encoding *); -static int btsco_set_params(void *, int, int, audio_params_t *, audio_params_t *); -static int btsco_round_blocksize(void *, int); -static int btsco_start_output(void *, void *, int, void (*)(void *), void *); -static int btsco_start_input(void *, void *, int, void (*)(void *), void *); -static int btsco_halt_output(void *); -static int btsco_halt_input(void *); -static int btsco_getdev(void *, struct audio_device *); -static int btsco_setfd(void *, int); -static int btsco_set_port(void *, mixer_ctrl_t *); -static int btsco_get_port(void *, mixer_ctrl_t *); -static int btsco_query_devinfo(void *, mixer_devinfo_t *); -static void *btsco_allocm(void *, int, size_t, int, int); -static void btsco_freem(void *, void *, int); -static int btsco_get_props(void *); -#ifdef notyet -static int btsco_dev_ioctl(void *, u_long, void *, int, struct proc *); -#endif - -struct audio_hw_if btsco_if = { - btsco_open, /* open */ - btsco_close, /* close */ - NULL, /* drain */ - btsco_query_encoding, /* query_encoding */ - btsco_set_params, /* set_params */ - btsco_round_blocksize, /* round_blocksize */ - NULL, /* commit_settings */ - NULL, /* init_output */ - NULL, /* init_input */ - btsco_start_output, /* start_output */ - btsco_start_input, /* start_input */ - btsco_halt_output, /* halt_output */ - btsco_halt_input, /* halt_input */ - NULL, /* speaker_ctl */ - btsco_getdev, /* getdev */ - btsco_setfd, /* setfd */ - btsco_set_port, /* set_port */ - btsco_get_port, /* get_port */ - btsco_query_devinfo, /* query_devinfo */ - btsco_allocm, /* allocm */ - btsco_freem, /* freem */ - NULL, /* round_buffersize */ - NULL, /* mappage */ - btsco_get_props, /* get_props */ - NULL, /* trigger_output */ - NULL, /* trigger_input */ - NULL /* get_default_params */ -}; - -static const struct audio_device btsco_device = { - "Bluetooth Audio", - "", - "btsco" -}; - -/* Voice_Setting == 0x0060: 8000Hz, mono, 16-bit, slinear_le */ -static const struct audio_format btsco_format = { - NULL, /* driver_data */ - (AUMODE_PLAY | AUMODE_RECORD), /* mode */ - AUDIO_ENCODING_SLINEAR_LE, /* encoding */ - 16, /* validbits */ - 16, /* precision */ - 1, /* channels */ - AUFMT_MONAURAL, /* channel_mask */ - 1, /* frequency_type */ - { 8000 } /* frequency */ -}; - -/* bluetooth(9) glue for SCO */ -static void btsco_sco_connecting(void *); -static void btsco_sco_connected(void *); -static void btsco_sco_disconnected(void *, int); -static void *btsco_sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); -static void btsco_sco_complete(void *, int); -static void btsco_sco_linkmode(void *, int); -static void btsco_sco_input(void *, struct mbuf *); - -static const struct btproto btsco_sco_proto = { - btsco_sco_connecting, - btsco_sco_connected, - btsco_sco_disconnected, - btsco_sco_newconn, - btsco_sco_complete, - btsco_sco_linkmode, - btsco_sco_input, -}; - - -/***************************************************************************** - * - * btsco definitions - */ - -/* - * btsco mixer class - */ -#define BTSCO_VGS 0 -#define BTSCO_VGM 1 -#define BTSCO_INPUT_CLASS 2 -#define BTSCO_OUTPUT_CLASS 3 - -/* connect timeout */ -#define BTSCO_TIMEOUT (30 * hz) - -/* misc btsco functions */ -static void btsco_extfree(caddr_t, u_int, void *); -static void btsco_intr(void *); - - -/***************************************************************************** - * - * btsco autoconf(9) routines - */ - -int -btsco_match(struct device *self, void *cfdata, void *aux) -{ - struct btdev_attach_args *bda = (struct btdev_attach_args *)aux; - - if (bda->bd_type == BTDEV_HSET || bda->bd_type == BTDEV_HF) - return 1; - - return 0; -} - -void -btsco_attach(struct device *parent, struct device *self, void *aux) -{ - struct btsco_softc *sc = (struct btsco_softc *)self; - struct btdev_attach_args *bda = aux; - - /* - * Init softc - */ - sc->sc_vgs = 200; - sc->sc_vgm = 200; - sc->sc_state = BTSCO_CLOSED; - sc->sc_name = self->dv_xname; - - /* - * copy in our configuration info - */ - bdaddr_copy(&sc->sc_laddr, &bda->bd_laddr); - bdaddr_copy(&sc->sc_raddr, &bda->bd_raddr); - - if (bda->bd_type == BTDEV_HF) { - sc->sc_flags |= BTSCO_LISTEN; - printf(" listen mode"); - } - - if (bda->bd_hset.hset_channel < RFCOMM_CHANNEL_MIN || - bda->bd_hset.hset_channel > RFCOMM_CHANNEL_MAX) { - printf(" invalid channel"); - return; - } - sc->sc_channel = bda->bd_hset.hset_channel; - - printf(" channel %d\n", sc->sc_channel); - - /* - * set up transmit interrupt - */ - timeout_set(&sc->sc_intr_to, btsco_intr, sc); - - /* - * attach audio device - */ - sc->sc_audio = audio_attach_mi(&btsco_if, sc, self); - if (sc->sc_audio == NULL) { - printf("%s: audio_attach_mi failed\n", sc->sc_dev.dv_xname); - return; - } -} - -int -btsco_detach(struct device *self, int flags) -{ - struct btsco_softc *sc = (struct btsco_softc *)self; - - DPRINTF("sc=%p\n", sc); - - mutex_enter(&bt_lock); - if (sc->sc_sco != NULL) { - DPRINTF("sc_sco=%p\n", sc->sc_sco); - sco_disconnect(sc->sc_sco, 0); - sco_detach(&sc->sc_sco); - sc->sc_sco = NULL; - } - - if (sc->sc_sco_l != NULL) { - DPRINTF("sc_sco_l=%p\n", sc->sc_sco_l); - sco_detach(&sc->sc_sco_l); - sc->sc_sco_l = NULL; - } - mutex_exit(&bt_lock); - - if (sc->sc_audio != NULL) { - DPRINTF("sc_audio=%p\n", sc->sc_audio); - config_detach(sc->sc_audio, flags); - sc->sc_audio = NULL; - } - - timeout_del(&sc->sc_intr_to); - - if (sc->sc_rx_mbuf != NULL) { - m_freem(sc->sc_rx_mbuf); - sc->sc_rx_mbuf = NULL; - } - - if (sc->sc_tx_refcnt > 0) { - printf("%s: tx_refcnt=%d!\n", sc->sc_dev.dv_xname, - sc->sc_tx_refcnt); - - if ((flags & DETACH_FORCE) == 0) - return EAGAIN; - } - - return 0; -} - -/***************************************************************************** - * - * bluetooth(9) methods for SCO - * - * All these are called from Bluetooth Protocol code, in a soft - * interrupt context at IPL_SOFTNET. - */ - -static void -btsco_sco_connecting(void *arg) -{ -/* struct btsco_softc *sc = arg; */ - - /* dont care */ -} - -static void -btsco_sco_connected(void *arg) -{ - struct btsco_softc *sc = arg; - - DPRINTF("%s\n", sc->sc_name); - - KASSERT(sc->sc_sco != NULL); - KASSERT(sc->sc_state == BTSCO_WAIT_CONNECT); - - /* - * If we are listening, no more need - */ - if (sc->sc_sco_l != NULL) - sco_detach(&sc->sc_sco_l); - - sc->sc_state = BTSCO_OPEN; - wakeup(&sc->sc_connect); -} - -static void -btsco_sco_disconnected(void *arg, int err) -{ - struct btsco_softc *sc = arg; - - DPRINTF("%s sc_state %d\n", sc->sc_name, sc->sc_state); - - KASSERT(sc->sc_sco != NULL); - - sc->sc_err = err; - sco_detach(&sc->sc_sco); - - switch (sc->sc_state) { - case BTSCO_CLOSED: /* dont think this can happen */ - break; - - case BTSCO_WAIT_CONNECT: /* connect failed */ - wakeup(&sc->sc_connect); - break; - - case BTSCO_OPEN: /* link lost */ - /* - * If IO is in progress, tell the audio driver that it - * has completed so that when it tries to send more, we - * can indicate an error. - */ - mtx_enter(&audio_lock); - if (sc->sc_tx_pending > 0) { - sc->sc_tx_pending = 0; - (*sc->sc_tx_intr)(sc->sc_tx_intrarg); - } - if (sc->sc_rx_want > 0) { - sc->sc_rx_want = 0; - (*sc->sc_rx_intr)(sc->sc_rx_intrarg); - } - mtx_leave(&audio_lock); - break; - - default: - UNKNOWN(sc->sc_state); - } - - sc->sc_state = BTSCO_CLOSED; -} - -static void * -btsco_sco_newconn(void *arg, struct sockaddr_bt *laddr, - struct sockaddr_bt *raddr) -{ - struct btsco_softc *sc = arg; - - DPRINTF("%s\n", sc->sc_name); - - if (bdaddr_same(&raddr->bt_bdaddr, &sc->sc_raddr) == 0 - || sc->sc_state != BTSCO_WAIT_CONNECT - || sc->sc_sco != NULL) - return NULL; - - sco_attach(&sc->sc_sco, &btsco_sco_proto, sc); - return sc->sc_sco; -} - -static void -btsco_sco_complete(void *arg, int count) -{ - struct btsco_softc *sc = arg; - - DPRINTFN(10, "%s count %d\n", sc->sc_name, count); - - mtx_enter(&audio_lock); - if (sc->sc_tx_pending > 0) { - sc->sc_tx_pending -= count; - if (sc->sc_tx_pending == 0) - (*sc->sc_tx_intr)(sc->sc_tx_intrarg); - } - mtx_leave(&audio_lock); -} - -static void -btsco_sco_linkmode(void *arg, int new) -{ -/* struct btsco_softc *sc = arg; */ - - /* dont care */ -} - -static void -btsco_sco_input(void *arg, struct mbuf *m) -{ - struct btsco_softc *sc = arg; - int len; - - DPRINTFN(10, "%s len=%d\n", sc->sc_name, m->m_pkthdr.len); - - mtx_enter(&audio_lock); - if (sc->sc_rx_want == 0) { - m_freem(m); - } else { - KASSERT(sc->sc_rx_intr != NULL); - KASSERT(sc->sc_rx_block != NULL); - - len = MIN(sc->sc_rx_want, m->m_pkthdr.len); - m_copydata(m, 0, len, sc->sc_rx_block); - - sc->sc_rx_want -= len; - sc->sc_rx_block += len; - - if (len > m->m_pkthdr.len) { - if (sc->sc_rx_mbuf != NULL) - m_freem(sc->sc_rx_mbuf); - - m_adj(m, len); - sc->sc_rx_mbuf = m; - } else { - m_freem(m); - } - - if (sc->sc_rx_want == 0) - (*sc->sc_rx_intr)(sc->sc_rx_intrarg); - } - mtx_leave(&audio_lock); -} - - -/***************************************************************************** - * - * audio(9) methods - * - */ - -static int -btsco_open(void *hdl, int flags) -{ - struct sockaddr_bt sa; - struct btsco_softc *sc = hdl; - int err, timo; - - DPRINTF("%s flags 0x%x\n", sc->sc_name, flags); - /* flags FREAD & FWRITE? */ - - if (sc->sc_sco != NULL || sc->sc_sco_l != NULL) - return EIO; - - mutex_enter(&bt_lock); - - memset(&sa, 0, sizeof(sa)); - sa.bt_len = sizeof(sa); - sa.bt_family = AF_BLUETOOTH; - bdaddr_copy(&sa.bt_bdaddr, &sc->sc_laddr); - - if (sc->sc_flags & BTSCO_LISTEN) { - err = sco_attach(&sc->sc_sco_l, &btsco_sco_proto, sc); - if (err) - goto done; - - err = sco_bind(sc->sc_sco_l, &sa); - if (err) { - sco_detach(&sc->sc_sco_l); - goto done; - } - - err = sco_listen(sc->sc_sco_l); - if (err) { - sco_detach(&sc->sc_sco_l); - goto done; - } - - timo = 0; /* no timeout */ - } else { - err = sco_attach(&sc->sc_sco, &btsco_sco_proto, sc); - if (err) - goto done; - - err = sco_bind(sc->sc_sco, &sa); - if (err) { - sco_detach(&sc->sc_sco); - goto done; - } - - bdaddr_copy(&sa.bt_bdaddr, &sc->sc_raddr); - err = sco_connect(sc->sc_sco, &sa); - if (err) { - sco_detach(&sc->sc_sco); - goto done; - } - - timo = BTSCO_TIMEOUT; - } - - sc->sc_state = BTSCO_WAIT_CONNECT; - while (err == 0 && sc->sc_state == BTSCO_WAIT_CONNECT) - err = msleep(&sc->sc_connect, &bt_lock, PWAIT, - "connect", timo); - - switch (sc->sc_state) { - case BTSCO_CLOSED: /* disconnected */ - err = sc->sc_err; - - /* fall through to */ - case BTSCO_WAIT_CONNECT: /* error */ - if (sc->sc_sco != NULL) - sco_detach(&sc->sc_sco); - - if (sc->sc_sco_l != NULL) - sco_detach(&sc->sc_sco_l); - - break; - - case BTSCO_OPEN: /* hurrah */ - (void)sco_getopt(sc->sc_sco, SO_SCO_MTU, &sc->sc_mtu); - break; - - default: - UNKNOWN(sc->sc_state); - break; - } - -done: - mutex_exit(&bt_lock); - - DPRINTF("done err=%d, sc_state=%d, sc_mtu=%d\n", - err, sc->sc_state, sc->sc_mtu); - return err; -} - -static void -btsco_close(void *hdl) -{ - struct btsco_softc *sc = hdl; - - DPRINTF("%s\n", sc->sc_name); - - mutex_enter(&bt_lock); - if (sc->sc_sco != NULL) { - sco_disconnect(sc->sc_sco, 0); - sco_detach(&sc->sc_sco); - } - - if (sc->sc_sco_l != NULL) { - sco_detach(&sc->sc_sco_l); - } - mutex_exit(&bt_lock); - - if (sc->sc_rx_mbuf != NULL) { - m_freem(sc->sc_rx_mbuf); - sc->sc_rx_mbuf = NULL; - } - - sc->sc_rx_want = 0; - sc->sc_rx_block = NULL; - sc->sc_rx_intr = NULL; - sc->sc_rx_intrarg = NULL; - - sc->sc_tx_size = 0; - sc->sc_tx_block = NULL; - sc->sc_tx_pending = 0; - sc->sc_tx_intr = NULL; - sc->sc_tx_intrarg = NULL; -} - -static int -btsco_query_encoding(void *hdl, struct audio_encoding *ae) -{ -/* struct btsco_softc *sc = hdl; */ - int err = 0; - - switch (ae->index) { - case 0: - strlcpy(ae->name, AudioEslinear_le, sizeof(ae->name)); - ae->encoding = AUDIO_ENCODING_SLINEAR_LE; - ae->precision = 16; - ae->flags = 0; - break; - default: - err = EINVAL; - } - ae->bps = AUDIO_BPS(ae->precision); - ae->msb = 1; - - return err; -} - -static int -btsco_set_params(void *hdl, int setmode, int usemode, - audio_params_t *play, audio_params_t *rec) -{ - int i, mode; - struct audio_params *p; - - DPRINTF("setmode 0x%x usemode 0x%x\n", setmode, usemode); - DPRINTF("rate %d, precision %d, channels %d encoding %d\n", - play->sample_rate, play->precision, play->channels, play->encoding); - - /* - * If we had a list of formats, we could check the HCI_Voice_Setting - * and select the appropriate one to use. Currently only one is - * supported: 0x0060 == 8000Hz, mono, 16-bit, slinear_le - */ - for (i = 0; i < 2; i++) { - if (i) { - mode = AUMODE_RECORD; - p = rec; - } else { - mode = AUMODE_PLAY; - p = play; - } - if (!(setmode & mode)) - continue; - p->sample_rate = 8000; - p->encoding = AUDIO_ENCODING_SLINEAR_LE; - p->precision = 16; - p->bps = 2; - p->msb = 1; - p->channels = 1; - } - return 0; -} - -/* - * If we have an MTU value to use, round the blocksize to that. - */ -static int -btsco_round_blocksize(void *hdl, int bs) -{ - struct btsco_softc *sc = hdl; - - if (sc->sc_mtu > 0) { - bs = (bs / sc->sc_mtu) * sc->sc_mtu; - if (bs == 0) - bs = sc->sc_mtu; - } - - DPRINTF("%s bs=%d, sc_mtu=%d\n", - sc->sc_name, bs, sc->sc_mtu); - - return bs; -} - -/* - * Start Output - * - * We dont want to be calling the network stack at splaudio() so make - * a note of what is to be sent, and schedule an interrupt to bundle - * it up and queue it. - */ -static int -btsco_start_output(void *hdl, void *block, int blksize, - void (*intr)(void *), void *intrarg) -{ - struct btsco_softc *sc = hdl; - - DPRINTFN(5, "%s blksize %d\n", sc->sc_name, blksize); - - if (sc->sc_sco == NULL) - return ENOTCONN; /* connection lost */ - - sc->sc_tx_block = block; - sc->sc_tx_pending = 0; - sc->sc_tx_size = blksize; - sc->sc_tx_intr = intr; - sc->sc_tx_intrarg = intrarg; - - timeout_add(&sc->sc_intr_to, 0); - return 0; -} - -/* - * Start Input - * - * When the SCO link is up, we are getting data in any case, so all we do - * is note what we want and where to put it and let the sco_input routine - * fill in the data. - * - * If there was any leftover data that didnt fit in the last block, retry - * it now. - */ -static int -btsco_start_input(void *hdl, void *block, int blksize, - void (*intr)(void *), void *intrarg) -{ - struct btsco_softc *sc = hdl; - struct mbuf *m; - - DPRINTFN(5, "%s blksize %d\n", sc->sc_name, blksize); - - if (sc->sc_sco == NULL) - return ENOTCONN; - - sc->sc_rx_want = blksize; - sc->sc_rx_block = block; - sc->sc_rx_intr = intr; - sc->sc_rx_intrarg = intrarg; - - if (sc->sc_rx_mbuf != NULL) { - m = sc->sc_rx_mbuf; - sc->sc_rx_mbuf = NULL; - btsco_sco_input(sc, m); - } - - return 0; -} - -/* - * Halt Output - * - * This doesnt really halt the output, but it will look - * that way to the audio driver. The current block will - * still be transmitted. - */ -static int -btsco_halt_output(void *hdl) -{ - struct btsco_softc *sc = hdl; - - DPRINTFN(5, "%s\n", sc->sc_name); - - sc->sc_tx_size = 0; - sc->sc_tx_block = NULL; - sc->sc_tx_pending = 0; - sc->sc_tx_intr = NULL; - sc->sc_tx_intrarg = NULL; - - return 0; -} - -/* - * Halt Input - * - * This doesnt really halt the input, but it will look - * that way to the audio driver. Incoming data will be - * discarded. - */ -static int -btsco_halt_input(void *hdl) -{ - struct btsco_softc *sc = hdl; - - DPRINTFN(5, "%s\n", sc->sc_name); - - sc->sc_rx_want = 0; - sc->sc_rx_block = NULL; - sc->sc_rx_intr = NULL; - sc->sc_rx_intrarg = NULL; - - if (sc->sc_rx_mbuf != NULL) { - m_freem(sc->sc_rx_mbuf); - sc->sc_rx_mbuf = NULL; - } - - return 0; -} - -static int -btsco_getdev(void *hdl, struct audio_device *ret) -{ - - *ret = btsco_device; - return 0; -} - -static int -btsco_setfd(void *hdl, int fd) -{ - DPRINTF("set %s duplex\n", fd ? "full" : "half"); - - return 0; -} - -static int -btsco_set_port(void *hdl, mixer_ctrl_t *mc) -{ - struct btsco_softc *sc = hdl; - int err = 0; - - DPRINTF("%s dev %d type %d\n", sc->sc_name, mc->dev, mc->type); - - switch (mc->dev) { - case BTSCO_VGS: - if (mc->type != AUDIO_MIXER_VALUE || - mc->un.value.num_channels != 1) { - err = EINVAL; - break; - } - - sc->sc_vgs = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; - break; - - case BTSCO_VGM: - if (mc->type != AUDIO_MIXER_VALUE || - mc->un.value.num_channels != 1) { - err = EINVAL; - break; - } - - sc->sc_vgm = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]; - break; - - default: - err = EINVAL; - break; - } - - return err; -} - -static int -btsco_get_port(void *hdl, mixer_ctrl_t *mc) -{ - struct btsco_softc *sc = hdl; - int err = 0; - - DPRINTF("%s dev %d\n", sc->sc_name, mc->dev); - - switch (mc->dev) { - case BTSCO_VGS: - mc->type = AUDIO_MIXER_VALUE; - mc->un.value.num_channels = 1; - mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_vgs; - break; - - case BTSCO_VGM: - mc->type = AUDIO_MIXER_VALUE; - mc->un.value.num_channels = 1; - mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_vgm; - break; - - default: - err = EINVAL; - break; - } - - return err; -} - -static int -btsco_query_devinfo(void *hdl, mixer_devinfo_t *di) -{ -/* struct btsco_softc *sc = hdl; */ - int err = 0; - - switch(di->index) { - case BTSCO_VGS: - di->mixer_class = BTSCO_OUTPUT_CLASS; - di->next = di->prev = AUDIO_MIXER_LAST; - strlcpy(di->label.name, AudioNspeaker, - sizeof(di->label.name)); - di->type = AUDIO_MIXER_VALUE; - strlcpy(di->un.v.units.name, AudioNvolume, - sizeof(di->un.v.units.name)); - di->un.v.num_channels = 1; - di->un.v.delta = BTSCO_DELTA; - break; - - case BTSCO_VGM: - di->mixer_class = BTSCO_INPUT_CLASS; - di->next = di->prev = AUDIO_MIXER_LAST; - strlcpy(di->label.name, AudioNmicrophone, - sizeof(di->label.name)); - di->type = AUDIO_MIXER_VALUE; - strlcpy(di->un.v.units.name, AudioNvolume, - sizeof(di->un.v.units.name)); - di->un.v.num_channels = 1; - di->un.v.delta = BTSCO_DELTA; - break; - - case BTSCO_INPUT_CLASS: - di->mixer_class = BTSCO_INPUT_CLASS; - di->next = di->prev = AUDIO_MIXER_LAST; - strlcpy(di->label.name, AudioCinputs, - sizeof(di->label.name)); - di->type = AUDIO_MIXER_CLASS; - break; - - case BTSCO_OUTPUT_CLASS: - di->mixer_class = BTSCO_OUTPUT_CLASS; - di->next = di->prev = AUDIO_MIXER_LAST; - strlcpy(di->label.name, AudioCoutputs, - sizeof(di->label.name)); - di->type = AUDIO_MIXER_CLASS; - break; - - default: - err = ENXIO; - break; - } - - return err; -} - -/* - * Allocate Ring Buffers. - */ -static void * -btsco_allocm(void *hdl, int direction, size_t size, int pool, int flags) -{ - struct btsco_softc *sc = hdl; - void *addr; - - DPRINTF("%s: size %d direction %d\n", sc->sc_name, size, direction); - - addr = malloc(size, pool, flags); - - if (direction == AUMODE_PLAY) { - sc->sc_tx_buf = addr; - sc->sc_tx_refcnt = 0; - } - - return addr; -} - -/* - * Free Ring Buffers. - * - * Because we used external memory for the tx mbufs, we dont - * want to free the memory until all the mbufs are done with - * - * Just to be sure, dont free if something is still pending. - * This would be a memory leak but at least there is a warning.. - */ -static void -btsco_freem(void *hdl, void *addr, int pool) -{ - struct btsco_softc *sc = hdl; - int count = hz / 2; - - if (addr == sc->sc_tx_buf) { - DPRINTF("%s: tx_refcnt=%d\n", sc->sc_name, sc->sc_tx_refcnt); - - sc->sc_tx_buf = NULL; - - while (sc->sc_tx_refcnt> 0 && count-- > 0) - tsleep(sc, PWAIT, "drain", 1); - - if (sc->sc_tx_refcnt > 0) { - printf("%s: ring buffer unreleased!\n", sc->sc_name); - return; - } - } - - free(addr, pool); -} - -static int -btsco_get_props(void *hdl) -{ - - return AUDIO_PROP_FULLDUPLEX; -} - -#ifdef notyet -/* - * Handle private ioctl. We pass information out about how to talk - * to the device and mixer. - */ -static int -btsco_dev_ioctl(void *hdl, u_long cmd, void *addr, int flag, - struct proc *l) -{ - struct btsco_softc *sc = hdl; - struct btsco_info *bi = (struct btsco_info *)addr; - int err = 0; - - DPRINTF("%s cmd 0x%lx flag %d\n", sc->sc_name, cmd, flag); - - switch (cmd) { - case BTSCO_GETINFO: - memset(bi, 0, sizeof(*bi)); - bdaddr_copy(&bi->laddr, &sc->sc_laddr); - bdaddr_copy(&bi->raddr, &sc->sc_raddr); - bi->channel = sc->sc_channel; - bi->vgs = BTSCO_VGS; - bi->vgm = BTSCO_VGM; - break; - - default: - err = ENOTTY; - break; - } - - return err; -} -#endif - - -/***************************************************************************** - * - * misc btsco functions - * - */ - -/* - * Our transmit interrupt. This is triggered when a new block is to be - * sent. We send mtu sized chunks of the block as mbufs with external - * storage to sco_send() - */ -static void -btsco_intr(void *arg) -{ - struct btsco_softc *sc = arg; - struct mbuf *m; - uint8_t *block; - int mlen, size; - int s; - - DPRINTFN(10, "%s block %p size %d\n", - sc->sc_name, sc->sc_tx_block, sc->sc_tx_size); - - if (sc->sc_sco == NULL) - return; /* connection is lost */ - - s = splsoftnet(); - - block = sc->sc_tx_block; - size = sc->sc_tx_size; - sc->sc_tx_block = NULL; - sc->sc_tx_size = 0; - - mutex_enter(&bt_lock); - while (size > 0) { - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - break; - - mlen = MIN(sc->sc_mtu, size); - - /* I think M_DEVBUF is true but not relevant */ - MEXTADD(m, block, mlen, M_DEVBUF, btsco_extfree, sc); - if ((m->m_flags & M_EXT) == 0) { - m_free(m); - break; - } - sc->sc_tx_refcnt++; - - m->m_pkthdr.len = m->m_len = mlen; - sc->sc_tx_pending++; - - if (sco_send(sc->sc_sco, m) > 0) { - sc->sc_tx_pending--; - break; - } - - block += mlen; - size -= mlen; - } - mutex_exit(&bt_lock); - - splx(s); -} - -/* - * Release the mbuf, we keep a reference count on the tx buffer so - * that we dont release it before its free. - */ -static void -btsco_extfree(caddr_t buf, u_int size, void *arg) -{ - struct btsco_softc *sc = arg; - -#ifdef notyet - if (m != NULL) - pool_cache_put(mb_cache, m); -#endif - - sc->sc_tx_refcnt--; -} diff --git a/sys/dev/bluetooth/btsco.h b/sys/dev/bluetooth/btsco.h deleted file mode 100644 index 5f7ce449d67..00000000000 --- a/sys/dev/bluetooth/btsco.h +++ /dev/null @@ -1,61 +0,0 @@ -/* $OpenBSD: btsco.h,v 1.1 2008/11/24 22:31:19 uwe Exp $ */ -/* $NetBSD: btsco.h,v 1.2 2006/09/10 15:45:56 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _DEV_BLUETOOTH_BTSCO_H_ -#define _DEV_BLUETOOTH_BTSCO_H_ - -#include <netbt/bluetooth.h> - -/* btsco(4) properties */ -#define BTSCOlisten "listen" -#define BTSCOchannel "rfcomm-channel" - -/* - * We need to provide a way to get the SCO Audio contact information - * from the audio device so that the control channel can be set up - */ - -struct btsco_info { - bdaddr_t laddr; /* controller addr */ - bdaddr_t raddr; /* remote addr */ - uint8_t channel; /* RFCOMM channel */ - int vgs; /* mixer index speaker */ - int vgm; /* mixer index mic */ -}; - -#define BTSCO_GETINFO _IOR('b', 16, struct btsco_info) - -#define BTSCO_DELTA 16 /* volume delta */ - -#endif /* _DEV_BLUETOOTH_BTSCO_H_ */ diff --git a/sys/dev/bluetooth/files.bluetooth b/sys/dev/bluetooth/files.bluetooth deleted file mode 100644 index 7f3678bf4a1..00000000000 --- a/sys/dev/bluetooth/files.bluetooth +++ /dev/null @@ -1,32 +0,0 @@ -# $OpenBSD: files.bluetooth,v 1.7 2010/07/31 16:04:50 miod Exp $ -# -# Config file and device description for machine-independent Bluetooth code. -# Included by ports that support Bluetooth host controllers. - -device bthub {} -attach bthub at btbus -file dev/bluetooth/bthub.c bthub needs-flag - -# HID -# HID "bus" -define bthidbus {[ reportid = -1 ]} - -# HID Device -device bthidev: bluetooth, bthidbus, hid -attach bthidev at bthub -file dev/bluetooth/bthidev.c bthidev - -# HID Mice -device btms: hid, hidms, wsmousedev -attach btms at bthidbus -file dev/bluetooth/btms.c btms - -# HID Keyboard -device btkbd: hid, hidkbd, wskbddev -attach btkbd at bthidbus -file dev/bluetooth/btkbd.c btkbd - -# SCO Audio -device btsco: bluetooth, audio, auconv, mulaw -attach btsco at bthub -file dev/bluetooth/btsco.c btsco diff --git a/sys/dev/sdmmc/files.sdmmc b/sys/dev/sdmmc/files.sdmmc index 0212c702145..b90aaff855c 100644 --- a/sys/dev/sdmmc/files.sdmmc +++ b/sys/dev/sdmmc/files.sdmmc @@ -1,4 +1,4 @@ -# $OpenBSD: files.sdmmc,v 1.3 2007/05/31 18:45:09 uwe Exp $ +# $OpenBSD: files.sdmmc,v 1.4 2014/07/11 21:54:38 tedu Exp $ # # Config file and device description for machine-independent SD/MMC code. # Included by ports that need it. @@ -11,8 +11,3 @@ file dev/sdmmc/sdmmc_cis.c sdmmc file dev/sdmmc/sdmmc_io.c sdmmc file dev/sdmmc/sdmmc_mem.c sdmmc file dev/sdmmc/sdmmc_scsi.c sdmmc - -# Bluetooth SDIO cards (Type-A/B) -device sbt: btbus, bluetooth -attach sbt at sdmmc -file dev/sdmmc/sbt.c sbt diff --git a/sys/dev/sdmmc/sbt.c b/sys/dev/sdmmc/sbt.c deleted file mode 100644 index bc62c4b1bb1..00000000000 --- a/sys/dev/sdmmc/sbt.c +++ /dev/null @@ -1,582 +0,0 @@ -/* $OpenBSD: sbt.c,v 1.17 2010/08/24 14:52:23 blambert Exp $ */ - -/* - * Copyright (c) 2007 Uwe Stuehler <uwe@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* Driver for Type-A/B SDIO Bluetooth cards */ - -#include <sys/param.h> -#include <sys/device.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/systm.h> - -#include <netbt/hci.h> - -#include <dev/sdmmc/sdmmcdevs.h> -#include <dev/sdmmc/sdmmcvar.h> - -#define CSR_READ_1(sc, reg) sdmmc_io_read_1((sc)->sc_sf, (reg)) -#define CSR_WRITE_1(sc, reg, val) sdmmc_io_write_1((sc)->sc_sf, (reg), (val)) - -#define SBT_REG_DAT 0x00 /* receiver/transmitter data */ -#define SBT_REG_RPC 0x10 /* read packet control */ -#define RPC_PCRRT (1<<0) /* packet read retry */ -#define SBT_REG_WPC 0x11 /* write packet control */ -#define WPC_PCWRT (1<<0) /* packet write retry */ -#define SBT_REG_RC 0x12 /* retry control status/set */ -#define SBT_REG_ISTAT 0x13 /* interrupt status */ -#define ISTAT_INTRD (1<<0) /* packet available for read */ -#define SBT_REG_ICLR 0x13 /* interrupt clear */ -#define SBT_REG_IENA 0x14 /* interrupt enable */ -#define SBT_REG_BTMODE 0x20 /* SDIO Bluetooth card mode */ -#define BTMODE_TYPEB (1<<0) /* 1=Type-B, 0=Type-A */ - -#define SBT_PKT_BUFSIZ 65540 -#define SBT_RXTRY_MAX 5 - -struct sbt_softc { - struct device sc_dev; /* base device */ - struct sdmmc_function *sc_sf; /* SDIO function */ - struct workq *sc_workq; /* transfer deferred packets */ - int sc_enabled; /* HCI enabled */ - int sc_dying; /* shutdown in progress */ - int sc_busy; /* transmitting or receiving */ - void *sc_ih; - u_char *sc_buf; - int sc_rxtry; - - struct hci_unit *sc_unit; /* MI host controller */ - struct bt_stats sc_stats; /* MI bluetooth stats */ - struct ifqueue sc_cmdq; - struct ifqueue sc_acltxq; - struct ifqueue sc_scotxq; -}; - -int sbt_match(struct device *, void *, void *); -void sbt_attach(struct device *, struct device *, void *); -int sbt_detach(struct device *, int); - -int sbt_write_packet(struct sbt_softc *, u_char *, size_t); -int sbt_read_packet(struct sbt_softc *, u_char *, size_t *); - -int sbt_intr(void *); - -int sbt_enable(struct device *); -void sbt_disable(struct device *); -void sbt_start(struct sbt_softc *, struct mbuf *, struct ifqueue *, int); -void sbt_xmit_cmd(struct device *, struct mbuf *); -void sbt_xmit_acl(struct device *, struct mbuf *); -void sbt_xmit_sco(struct device *, struct mbuf *); -void sbt_start_task(void *, void *); - -void sbt_stats(struct device *, struct bt_stats *, int); - -#undef DPRINTF -#define SBT_DEBUG -#ifdef SBT_DEBUG -int sbt_debug = 0; -#define DPRINTF(s) printf s -#define DNPRINTF(n, s) do { if ((n) <= sbt_debug) printf s; } while (0) -#else -#define DPRINTF(s) do {} while (0) -#define DNPRINTF(n, s) do {} while (0) -#endif - -struct cfattach sbt_ca = { - sizeof(struct sbt_softc), sbt_match, sbt_attach, sbt_detach -}; - -struct cfdriver sbt_cd = { - NULL, "sbt", DV_DULL -}; - - -/* - * Autoconf glue - */ - -static const struct sbt_product { - u_int16_t sp_vendor; - u_int16_t sp_product; - const char *sp_cisinfo[4]; -} sbt_products[] = { - { SDMMC_VENDOR_SOCKETCOM, - SDMMC_PRODUCT_SOCKETCOM_BTCARD, - SDMMC_CIS_SOCKETCOM_BTCARD } -}; - -const struct hci_if sbt_hci = { - .enable = sbt_enable, - .disable = sbt_disable, - .output_cmd = sbt_xmit_cmd, - .output_acl = sbt_xmit_acl, - .output_sco = sbt_xmit_sco, - .get_stats = sbt_stats, - .ipl = IPL_SDMMC -}; - -int -sbt_match(struct device *parent, void *match, void *aux) -{ - struct sdmmc_attach_args *sa = aux; - const struct sbt_product *sp; - struct sdmmc_function *sf; - int i; - - if (sa->sf == NULL) - return 0; /* not SDIO */ - - sf = sa->sf->sc->sc_fn0; - sp = &sbt_products[0]; - - for (i = 0; i < sizeof(sbt_products) / sizeof(sbt_products[0]); - i++, sp = &sbt_products[i]) - if (sp->sp_vendor == sf->cis.manufacturer && - sp->sp_product == sf->cis.product) - return 1; - return 0; -} - -void -sbt_attach(struct device *parent, struct device *self, void *aux) -{ - struct sbt_softc *sc = (struct sbt_softc *)self; - struct sdmmc_attach_args *sa = aux; - - SDMMC_ASSERT_LOCKED(sc->sc_sf->sc); - - printf("\n"); - - sc->sc_sf = sa->sf; - - (void)sdmmc_io_function_disable(sc->sc_sf); - if (sdmmc_io_function_enable(sc->sc_sf)) { - printf("%s: function not ready\n", DEVNAME(sc)); - return; - } - - /* It may be Type-B, but we use it only in Type-A mode. */ - printf("%s: SDIO Bluetooth Type-A\n", DEVNAME(sc)); - - /* Create a shared buffer for receive and transmit. */ - sc->sc_buf = malloc(SBT_PKT_BUFSIZ, M_DEVBUF, M_NOWAIT); - if (sc->sc_buf == NULL) { - printf("%s: can't allocate cmd buffer\n", DEVNAME(sc)); - return; - } - - /* Create a work thread to transmit deferred packets. */ - sc->sc_workq = workq_create(DEVNAME(sc), 1, IPL_SDMMC); - if (sc->sc_workq == NULL) { - printf("%s: can't allocate workq\n", DEVNAME(sc)); - return; - } - - /* Enable the HCI packet transport read interrupt. */ - CSR_WRITE_1(sc, SBT_REG_IENA, ISTAT_INTRD); - - /* Enable the card interrupt for this function. */ - sc->sc_ih = sdmmc_intr_establish(parent, sbt_intr, sc, DEVNAME(sc)); - if (sc->sc_ih == NULL) { - printf("%s: can't establish interrupt\n", DEVNAME(sc)); - return; - } - sdmmc_intr_enable(sc->sc_sf); - - /* - * Attach Bluetooth unit (machine-independent HCI). - */ - sc->sc_unit = hci_attach(&sbt_hci, &sc->sc_dev, 0); -} - -int -sbt_detach(struct device *self, int flags) -{ - struct sbt_softc *sc = (struct sbt_softc *)self; - - sc->sc_dying = 1; - - while (sc->sc_busy) - tsleep(&sc->sc_busy, PWAIT, "sbtdie", 0); - - /* Detach HCI interface */ - if (sc->sc_unit) { - hci_detach(sc->sc_unit); - sc->sc_unit = NULL; - } - - if (sc->sc_ih != NULL) - sdmmc_intr_disestablish(sc->sc_ih); - - if (sc->sc_workq != NULL) - workq_destroy(sc->sc_workq); - - if (sc->sc_buf != NULL) - free(sc->sc_buf, M_DEVBUF); - - return 0; -} - - -/* - * Bluetooth HCI packet transport - */ - -int -sbt_write_packet(struct sbt_softc *sc, u_char *buf, size_t len) -{ - u_char hdr[3]; - size_t pktlen; - int error = EIO; - int retry = 3; - -again: - if (retry-- == 0) { - DPRINTF(("%s: sbt_write_cmd: giving up\n", DEVNAME(sc))); - return error; - } - - /* Restart the current packet. */ - sdmmc_io_write_1(sc->sc_sf, SBT_REG_WPC, WPC_PCWRT); - - /* Write the packet length. */ - pktlen = len + 3; - hdr[0] = pktlen & 0xff; - hdr[1] = (pktlen >> 8) & 0xff; - hdr[2] = (pktlen >> 16) & 0xff; - error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3); - if (error) { - DPRINTF(("%s: sbt_write_packet: failed to send length\n", - DEVNAME(sc))); - goto again; - } - - error = sdmmc_io_write_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len); - if (error) { - DPRINTF(("%s: sbt_write_packet: failed to send packet data\n", - DEVNAME(sc))); - goto again; - } - return 0; -} - -int -sbt_read_packet(struct sbt_softc *sc, u_char *buf, size_t *lenp) -{ - u_char hdr[3]; - size_t len; - int error; - - error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, hdr, 3); - if (error) { - DPRINTF(("%s: sbt_read_packet: failed to read length\n", - DEVNAME(sc))); - goto out; - } - len = (hdr[0] | (hdr[1] << 8) | (hdr[2] << 16)) - 3; - if (len > *lenp) { - DPRINTF(("%s: sbt_read_packet: len %u > %u\n", - DEVNAME(sc), len, *lenp)); - error = ENOBUFS; - goto out; - } - - DNPRINTF(2,("%s: sbt_read_packet: reading len %u bytes\n", - DEVNAME(sc), len)); - error = sdmmc_io_read_multi_1(sc->sc_sf, SBT_REG_DAT, buf, len); - if (error) { - DPRINTF(("%s: sbt_read_packet: failed to read packet data\n", - DEVNAME(sc))); - goto out; - } - -out: - rw_enter_write(&sc->sc_sf->sc->sc_lock); - if (error) { - if (sc->sc_rxtry >= SBT_RXTRY_MAX) { - /* Drop and request the next packet. */ - sc->sc_rxtry = 0; - CSR_WRITE_1(sc, SBT_REG_RPC, 0); - } else { - /* Request the current packet again. */ - sc->sc_rxtry++; - CSR_WRITE_1(sc, SBT_REG_RPC, RPC_PCRRT); - } - rw_exit(&sc->sc_sf->sc->sc_lock); - return error; - } - - /* acknowledge read packet */ - CSR_WRITE_1(sc, SBT_REG_RPC, 0); - - rw_exit(&sc->sc_sf->sc->sc_lock); - - *lenp = len; - return 0; -} - -/* - * Interrupt handling - */ - -/* This function is called from the SDIO interrupt thread. */ -int -sbt_intr(void *arg) -{ - struct sbt_softc *sc = arg; - struct mbuf *m = NULL; - u_int8_t status; - size_t len; - int s; - - /* Block further SDIO interrupts; XXX not really needed? */ - s = splsdmmc(); - - rw_enter_write(&sc->sc_sf->sc->sc_lock); - status = CSR_READ_1(sc, SBT_REG_ISTAT); - CSR_WRITE_1(sc, SBT_REG_ICLR, status); - rw_exit(&sc->sc_sf->sc->sc_lock); - - if ((status & ISTAT_INTRD) == 0) - return 0; /* shared SDIO card interrupt? */ - - len = SBT_PKT_BUFSIZ; - if (sbt_read_packet(sc, sc->sc_buf, &len) != 0 || len == 0) { - DPRINTF(("%s: sbt_intr: read failed\n", DEVNAME(sc))); - goto eoi; - } - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) { - DPRINTF(("%s: sbt_intr: MGETHDR failed\n", DEVNAME(sc))); - goto eoi; - } - - m->m_pkthdr.len = m->m_len = MHLEN; - m_copyback(m, 0, len, sc->sc_buf, M_NOWAIT); - if (m->m_pkthdr.len == MAX(MHLEN, len)) { - m->m_pkthdr.len = len; - m->m_len = MIN(MHLEN, m->m_pkthdr.len); - } else { - DPRINTF(("%s: sbt_intr: m_copyback failed\n", DEVNAME(sc))); - m_free(m); - m = NULL; - } - -eoi: - if (m != NULL) { - switch (sc->sc_buf[0]) { - case HCI_ACL_DATA_PKT: - DNPRINTF(1,("%s: recv ACL packet (%d bytes)\n", - DEVNAME(sc), m->m_pkthdr.len)); - hci_input_acl(sc->sc_unit, m); - break; - case HCI_SCO_DATA_PKT: - DNPRINTF(1,("%s: recv SCO packet (%d bytes)\n", - DEVNAME(sc), m->m_pkthdr.len)); - hci_input_sco(sc->sc_unit, m); - break; - case HCI_EVENT_PKT: - DNPRINTF(1,("%s: recv EVENT packet (%d bytes)\n", - DEVNAME(sc), m->m_pkthdr.len)); - hci_input_event(sc->sc_unit, m); - break; - default: - DPRINTF(("%s: recv 0x%x packet (%d bytes)\n", - DEVNAME(sc), sc->sc_buf[0], m->m_pkthdr.len)); - sc->sc_stats.err_rx++; - m_free(m); - break; - } - } else - sc->sc_stats.err_rx++; - - splx(s); - - /* Claim this interrupt. */ - return 1; -} - - -/* - * Bluetooth HCI unit functions - */ - -int -sbt_enable(struct device *self) -{ - struct sbt_softc *sc = (struct sbt_softc *)self; - - if (sc->sc_enabled) - return 0; - - sc->sc_enabled = 1; - return 0; -} - -void -sbt_disable(struct device *self) -{ - struct sbt_softc *sc = (struct sbt_softc *)self; - int s; - - if (!sc->sc_enabled) - return; - - s = splsdmmc(); -#ifdef notyet /* XXX */ - if (sc->sc_rxp) { - m_freem(sc->sc_rxp); - sc->sc_rxp = NULL; - } - - if (sc->sc_txp) { - m_freem(sc->sc_txp); - sc->sc_txp = NULL; - } -#endif - sc->sc_enabled = 0; - splx(s); -} - -void -sbt_start(struct sbt_softc *sc, struct mbuf *m, struct ifqueue *q, int xmit) -{ - int s; - int len; -#ifdef SBT_DEBUG - const char *what; -#endif - - s = splsdmmc(); - if (m != NULL) - IF_ENQUEUE(q, m); - - if (sc->sc_dying || IF_IS_EMPTY(q)) { - splx(s); - return; - } - - if (curproc == NULL || sc->sc_busy) { - (void)workq_add_task(sc->sc_workq, 0, sbt_start_task, - sc, (void *)(long)xmit); - splx(s); - return; - } - - /* Defer additional transfers and reception of packets. */ - sdmmc_intr_disable(sc->sc_sf); - sc->sc_busy++; - - IF_DEQUEUE(q, m); - -#ifdef SBT_DEBUG - switch (xmit) { - case BTF_XMIT_CMD: - what = "CMD"; - break; - case BTF_XMIT_ACL: - what = "ACL"; - break; - case BTF_XMIT_SCO: - what = "SCO"; - break; - } - DNPRINTF(1,("%s: xmit %s packet (%d bytes)\n", DEVNAME(sc), - what, m->m_pkthdr.len)); -#endif - - sc->sc_unit->hci_flags |= xmit; - - len = m->m_pkthdr.len; - m_copydata(m, 0, len, sc->sc_buf); - m_freem(m); - - if (sbt_write_packet(sc, sc->sc_buf, len)) - DPRINTF(("%s: sbt_write_packet failed\n", DEVNAME(sc))); - - sc->sc_unit->hci_flags &= ~xmit; - - sc->sc_busy--; - sdmmc_intr_enable(sc->sc_sf); - - if (sc->sc_dying) - wakeup(&sc->sc_busy); - - splx(s); -} - -void -sbt_xmit_cmd(struct device *self, struct mbuf *m) -{ - struct sbt_softc *sc = (struct sbt_softc *)self; - - sbt_start(sc, m, &sc->sc_cmdq, BTF_XMIT_CMD); -} - -void -sbt_xmit_acl(struct device *self, struct mbuf *m) -{ - struct sbt_softc *sc = (struct sbt_softc *)self; - - sbt_start(sc, m, &sc->sc_acltxq, BTF_XMIT_ACL); -} - -void -sbt_xmit_sco(struct device *self, struct mbuf *m) -{ - struct sbt_softc *sc = (struct sbt_softc *)self; - - sbt_start(sc, m, &sc->sc_scotxq, BTF_XMIT_SCO); -} - -void -sbt_start_task(void *arg1, void *arg2) -{ - struct sbt_softc *sc = arg1; - int xmit = (long)arg2; - - switch (xmit) { - case BTF_XMIT_CMD: - sbt_xmit_cmd(&sc->sc_dev, NULL); - break; - case BTF_XMIT_ACL: - sbt_xmit_acl(&sc->sc_dev, NULL); - break; - case BTF_XMIT_SCO: - sbt_xmit_sco(&sc->sc_dev, NULL); - break; - } -} - -void -sbt_stats(struct device *self, struct bt_stats *dest, int flush) -{ - struct sbt_softc *sc = (struct sbt_softc *)self; - int s; - - s = splsdmmc(); - memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats)); - - if (flush) - memset(&sc->sc_stats, 0, sizeof(struct bt_stats)); - - splx(s); -} diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb index 06729e6784e..907abcbf218 100644 --- a/sys/dev/usb/files.usb +++ b/sys/dev/usb/files.usb @@ -1,4 +1,4 @@ -# $OpenBSD: files.usb,v 1.114 2014/03/25 03:29:23 jsg Exp $ +# $OpenBSD: files.usb,v 1.115 2014/07/11 21:54:38 tedu Exp $ # $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $ # # Config file and device description for machine-independent USB code. @@ -354,11 +354,6 @@ device atu: ether, ifnet, ifmedia, wlan, firmload attach atu at uhub file dev/usb/if_atu.c atu -# Bluetooth -device ubt: btbus, bluetooth -attach ubt at uhub -file dev/usb/ubt.c ubt - # Ralink Technology RT2500USB device ural: ether, ifnet, ifmedia, wlan attach ural at uhub diff --git a/sys/dev/usb/ubt.c b/sys/dev/usb/ubt.c deleted file mode 100644 index 575e81c73e7..00000000000 --- a/sys/dev/usb/ubt.c +++ /dev/null @@ -1,1586 +0,0 @@ -/* $OpenBSD: ubt.c,v 1.26 2013/12/15 14:28:35 pirofti Exp $ */ -/* $NetBSD: ubt.c,v 1.35 2008/07/28 14:19:26 drochner Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/* - * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (lennart@augustsson.net) and - * David Sainty (David.Sainty@dtsp.co.nz). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This driver originally written by Lennart Augustsson and David Sainty, - * but was mostly rewritten for the NetBSD Bluetooth protocol stack by - * Iain Hibbert for Itronix, Inc using the FreeBSD ng_ubt.c driver as a - * reference. - */ - -#include <sys/param.h> -#include <sys/device.h> -#include <sys/ioctl.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/systm.h> -#include <sys/timeout.h> - -#include <dev/usb/usb.h> -#include <dev/usb/usbdi.h> -#include <dev/usb/usbdi_util.h> -#include <dev/usb/usbdevs.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> - -/******************************************************************************* - * - * debugging stuff - */ -#undef DPRINTF -#undef DPRINTFN - -#define UBT_DEBUG 0 -#ifdef UBT_DEBUG -int ubt_debug = UBT_DEBUG; - -#define DPRINTF(fmt, args...) do { \ - if (ubt_debug) \ - printf("%s: "fmt, __func__ , ##args); \ -} while (/* CONSTCOND */0) - -#define DPRINTFN(n, fmt, args...) do { \ - if (ubt_debug > (n)) \ - printf("%s: "fmt, __func__ , ##args); \ -} while (/* CONSTCOND */0) - -#else -#define DPRINTF(...) -#define DPRINTFN(...) -#endif - -/******************************************************************************* - * - * ubt softc structure - * - */ - -/* buffer sizes */ -/* - * NB: although ACL packets can extend to 65535 bytes, most devices - * have max_acl_size at much less (largest I have seen is 384) - */ -#define UBT_BUFSIZ_CMD (HCI_CMD_PKT_SIZE - 1) -#define UBT_BUFSIZ_ACL (2048 - 1) -#define UBT_BUFSIZ_EVENT (HCI_EVENT_PKT_SIZE - 1) - -/* Transmit timeouts */ -#define UBT_CMD_TIMEOUT USBD_DEFAULT_TIMEOUT -#define UBT_ACL_TIMEOUT USBD_DEFAULT_TIMEOUT - -/* - * ISOC transfers - * - * xfer buffer size depends on the frame size, and the number - * of frames per transfer is fixed, as each frame should be - * 1ms worth of data. This keeps the rate that xfers complete - * fairly constant. We use multiple xfers to keep the hardware - * busy - */ -#define UBT_NXFERS 3 /* max xfers to queue */ -#define UBT_NFRAMES 10 /* frames per xfer */ - -struct ubt_isoc_xfer { - struct ubt_softc *softc; - struct usbd_xfer *xfer; - uint8_t *buf; - uint16_t size[UBT_NFRAMES]; - int busy; -}; - -struct ubt_softc { - struct device sc_dev; - struct usbd_device *sc_udev; - int sc_refcnt; - int sc_enabled; - - /* Control Interface */ - struct usbd_interface *sc_iface0; - - /* Commands (control) */ - struct usbd_xfer *sc_cmd_xfer; - uint8_t *sc_cmd_buf; - int sc_cmd_busy; /* write active */ - struct ifqueue sc_cmd_queue; /* output queue */ - - /* Events (interrupt) */ - int sc_evt_addr; /* endpoint address */ - struct usbd_pipe *sc_evt_pipe; - uint8_t *sc_evt_buf; - - /* ACL data (in) */ - int sc_aclrd_addr; /* endpoint address */ - struct usbd_pipe *sc_aclrd_pipe; /* read pipe */ - struct usbd_xfer *sc_aclrd_xfer; /* read xfer */ - uint8_t *sc_aclrd_buf; /* read buffer */ - int sc_aclrd_busy; /* reading */ - - /* ACL data (out) */ - int sc_aclwr_addr; /* endpoint address */ - struct usbd_pipe *sc_aclwr_pipe; /* write pipe */ - struct usbd_xfer *sc_aclwr_xfer; /* write xfer */ - uint8_t *sc_aclwr_buf; /* write buffer */ - int sc_aclwr_busy; /* write active */ - struct ifqueue sc_aclwr_queue;/* output queue */ - - /* ISOC interface */ - struct usbd_interface *sc_iface1; /* ISOC interface */ - int sc_config; /* current config no */ - int sc_alt_config; /* no of alternates */ - - /* SCO data (in) */ - int sc_scord_addr; /* endpoint address */ - struct usbd_pipe *sc_scord_pipe; /* read pipe */ - int sc_scord_size; /* frame length */ - struct ubt_isoc_xfer sc_scord[UBT_NXFERS]; - struct mbuf *sc_scord_mbuf; /* current packet */ - - /* SCO data (out) */ - int sc_scowr_addr; /* endpoint address */ - struct usbd_pipe *sc_scowr_pipe; /* write pipe */ - int sc_scowr_size; /* frame length */ - struct ubt_isoc_xfer sc_scowr[UBT_NXFERS]; - struct mbuf *sc_scowr_mbuf; /* current packet */ - int sc_scowr_busy; /* write active */ - struct ifqueue sc_scowr_queue;/* output queue */ - - /* Protocol structure */ - struct hci_unit *sc_unit; - struct bt_stats sc_stats; - - /* Successfully attached */ - int sc_ok; -}; - -/* - * Bluetooth unit/USB callback routines - */ -int ubt_enable(struct device *); -void ubt_disable(struct device *); - -void ubt_xmit_cmd(struct device *, struct mbuf *); -void ubt_xmit_cmd_start(struct ubt_softc *); -void ubt_xmit_cmd_complete(struct usbd_xfer *, void *, usbd_status); - -void ubt_xmit_acl(struct device *, struct mbuf *); -void ubt_xmit_acl_start(struct ubt_softc *); -void ubt_xmit_acl_complete(struct usbd_xfer *, void *, usbd_status); - -void ubt_xmit_sco(struct device *, struct mbuf *); -void ubt_xmit_sco_start(struct ubt_softc *); -void ubt_xmit_sco_start1(struct ubt_softc *, struct ubt_isoc_xfer *); -void ubt_xmit_sco_complete(struct usbd_xfer *, void *, usbd_status); - -void ubt_recv_event(struct usbd_xfer *, void *, usbd_status); - -void ubt_recv_acl_start(struct ubt_softc *); -void ubt_recv_acl_complete(struct usbd_xfer *, void *, usbd_status); - -void ubt_recv_sco_start1(struct ubt_softc *, struct ubt_isoc_xfer *); -void ubt_recv_sco_complete(struct usbd_xfer *, void *, usbd_status); - -void ubt_stats(struct device *, struct bt_stats *, int); - -int ubt_match(struct device *, void *, void *); -void ubt_attach(struct device *, struct device *, void *); -int ubt_detach(struct device *, int); -int ubt_activate(struct device *, int); - -struct cfdriver ubt_cd = { - NULL, "ubt", DV_DULL -}; - -const struct cfattach ubt_ca = { - sizeof(struct ubt_softc), - ubt_match, - ubt_attach, - ubt_detach, - ubt_activate, -}; - -const struct hci_if ubt_hci = { - .enable = ubt_enable, - .disable = ubt_disable, - .output_cmd = ubt_xmit_cmd, - .output_acl = ubt_xmit_acl, - .output_sco = ubt_xmit_sco, - .get_stats = ubt_stats, - .ipl = IPL_USB, /* IPL_SOFTUSB ??? */ -}; - -static int ubt_set_isoc_config(struct ubt_softc *); -static void ubt_abortdealloc(struct ubt_softc *); - -/* - * Match against the whole device, since we want to take - * both interfaces. If a device should be ignored then add - * - * { VendorID, ProductID } - * - * to the ubt_ignore list. - */ -static const struct usb_devno ubt_ignore[] = { - { USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033NF } -}; - -int -ubt_match(struct device *parent, void *match, void *aux) -{ - struct usb_attach_arg *uaa = aux; - usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device); - - DPRINTFN(50, "ubt_match\n"); - - if (usb_lookup(ubt_ignore, uaa->vendor, uaa->product)) - return UMATCH_NONE; - - if (dd->bDeviceClass == UDCLASS_WIRELESS - && dd->bDeviceSubClass == UDSUBCLASS_RF - && dd->bDeviceProtocol == UDPROTO_BLUETOOTH) - return UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO; - - return UMATCH_NONE; -} - - -void -ubt_attach(struct device *parent, struct device *self, void *aux) -{ - struct ubt_softc *sc = (struct ubt_softc *)self; - struct usb_attach_arg *uaa = aux; - usb_config_descriptor_t *cd; - usb_endpoint_descriptor_t *ed; - int err; - uint8_t count, i; - - DPRINTFN(50, "ubt_attach: sc=%p\n", sc); - - sc->sc_udev = uaa->device; - -#ifndef __OpenBSD__ /* ??? */ - MBUFQ_INIT(&sc->sc_cmd_queue); - MBUFQ_INIT(&sc->sc_aclwr_queue); - MBUFQ_INIT(&sc->sc_scowr_queue); -#endif - - /* - * Move the device into the configured state - */ - err = usbd_set_config_index(sc->sc_udev, 0, 1); - if (err) { - printf("%s: failed to set configuration idx 0: %s\n", - sc->sc_dev.dv_xname, usbd_errstr(err)); - - return; - } - - /* - * Interface 0 must have 3 endpoints - * 1) Interrupt endpoint to receive HCI events - * 2) Bulk IN endpoint to receive ACL data - * 3) Bulk OUT endpoint to send ACL data - */ - err = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface0); - if (err) { - printf("%s: Could not get interface 0 handle %s (%d)\n", - sc->sc_dev.dv_xname, usbd_errstr(err), err); - - return; - } - - sc->sc_evt_addr = -1; - sc->sc_aclrd_addr = -1; - sc->sc_aclwr_addr = -1; - - count = 0; - (void)usbd_endpoint_count(sc->sc_iface0, &count); - - for (i = 0 ; i < count ; i++) { - int dir, type; - - ed = usbd_interface2endpoint_descriptor(sc->sc_iface0, i); - if (ed == NULL) { - printf("%s: could not read endpoint descriptor %d\n", - sc->sc_dev.dv_xname, i); - - return; - } - - dir = UE_GET_DIR(ed->bEndpointAddress); - type = UE_GET_XFERTYPE(ed->bmAttributes); - - if (dir == UE_DIR_IN && type == UE_INTERRUPT) - sc->sc_evt_addr = ed->bEndpointAddress; - else if (dir == UE_DIR_IN && type == UE_BULK) - sc->sc_aclrd_addr = ed->bEndpointAddress; - else if (dir == UE_DIR_OUT && type == UE_BULK) - sc->sc_aclwr_addr = ed->bEndpointAddress; - } - - if (sc->sc_evt_addr == -1) { - printf("%s: missing INTERRUPT endpoint on interface 0\n", - sc->sc_dev.dv_xname); - - return; - } - if (sc->sc_aclrd_addr == -1) { - printf("%s: missing BULK IN endpoint on interface 0\n", - sc->sc_dev.dv_xname); - - return; - } - if (sc->sc_aclwr_addr == -1) { - printf("%s: missing BULK OUT endpoint on interface 0\n", - sc->sc_dev.dv_xname); - - return; - } - - /* - * Interface 1 must have 2 endpoints - * 1) Isochronous IN endpoint to receive SCO data - * 2) Isochronous OUT endpoint to send SCO data - * - * and will have several configurations, which can be selected - * via a sysctl variable. We select config 0 to start, which - * means that no SCO data will be available. - */ - err = usbd_device2interface_handle(sc->sc_udev, 1, &sc->sc_iface1); - if (err) { - printf("%s: Could not get interface 1 handle %s (%d)\n", - sc->sc_dev.dv_xname, usbd_errstr(err), err); - - return; - } - - cd = usbd_get_config_descriptor(sc->sc_udev); - if (cd == NULL) { - printf("%s: could not get config descriptor\n", - sc->sc_dev.dv_xname); - - return; - } - - sc->sc_alt_config = usbd_get_no_alts(cd, 1); - - /* set initial config */ - err = ubt_set_isoc_config(sc); - if (err) { - printf("%s: ISOC config failed\n", - sc->sc_dev.dv_xname); - - return; - } - - /* Attach HCI */ - sc->sc_unit = hci_attach(&ubt_hci, &sc->sc_dev, 0); - - sc->sc_ok = 1; - /* XXX pmf_device_deregister in NetBSD (power hook) */ -} - -int -ubt_detach(struct device *self, int flags) -{ - struct ubt_softc *sc = (struct ubt_softc *)self; - int s; - - DPRINTF("sc=%p flags=%d\n", sc, flags); - - /* XXX pmf_device_deregister in NetBSD (power hook) */ - - if (!sc->sc_ok) - return 0; - - /* Detach HCI interface */ - if (sc->sc_unit) { - hci_detach(sc->sc_unit); - sc->sc_unit = NULL; - } - - /* - * Abort all pipes. Causes processes waiting for transfer to wake. - * - * Actually, hci_detach() above will call ubt_disable() which may - * call ubt_abortdealloc(), but lets be sure since doing it twice - * wont cause an error. - */ - ubt_abortdealloc(sc); - - /* wait for all processes to finish */ - s = splusb(); - if (sc->sc_refcnt-- > 0) - usb_detach_wait(&sc->sc_dev); - - splx(s); - - DPRINTFN(1, "driver detached\n"); - - return 0; -} - -int -ubt_activate(struct device *self, int act) -{ - struct ubt_softc *sc = (struct ubt_softc *)self; - - switch (act) { - case DVACT_DEACTIVATE: - usbd_deactivate(sc->sc_udev); - break; - } - return (0); -} - -/* set ISOC configuration */ -int -ubt_set_isoc_config(struct ubt_softc *sc) -{ - usb_endpoint_descriptor_t *ed; - int rd_addr, wr_addr, rd_size, wr_size; - uint8_t count, i; - int err; - - err = usbd_set_interface(sc->sc_iface1, sc->sc_config); - if (err != USBD_NORMAL_COMPLETION) { - printf( - "%s: Could not set config %d on ISOC interface. %s (%d)\n", - sc->sc_dev.dv_xname, sc->sc_config, usbd_errstr(err), err); - - return err == USBD_IN_USE ? EBUSY : EIO; - } - - /* - * We wont get past the above if there are any pipes open, so no - * need to worry about buf/xfer/pipe deallocation. If we get an - * error after this, the frame quantities will be 0 and no SCO - * data will be possible. - */ - - sc->sc_scord_size = rd_size = 0; - sc->sc_scord_addr = rd_addr = -1; - - sc->sc_scowr_size = wr_size = 0; - sc->sc_scowr_addr = wr_addr = -1; - - count = 0; - (void)usbd_endpoint_count(sc->sc_iface1, &count); - - for (i = 0 ; i < count ; i++) { - ed = usbd_interface2endpoint_descriptor(sc->sc_iface1, i); - if (ed == NULL) { - printf("%s: could not read endpoint descriptor %d\n", - sc->sc_dev.dv_xname, i); - - return EIO; - } - - DPRINTFN(5, "%s: endpoint type %02x (%02x) addr %02x (%s)\n", - sc->sc_dev.dv_xname, - UE_GET_XFERTYPE(ed->bmAttributes), - UE_GET_ISO_TYPE(ed->bmAttributes), - ed->bEndpointAddress, - UE_GET_DIR(ed->bEndpointAddress) ? "in" : "out"); - - if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_ISOCHRONOUS) - continue; - - if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) { - rd_addr = ed->bEndpointAddress; - rd_size = UGETW(ed->wMaxPacketSize); - } else { - wr_addr = ed->bEndpointAddress; - wr_size = UGETW(ed->wMaxPacketSize); - } - } - - if (rd_addr == -1) { - printf( - "%s: missing ISOC IN endpoint on interface config %d\n", - sc->sc_dev.dv_xname, sc->sc_config); - - return ENOENT; - } - if (wr_addr == -1) { - printf( - "%s: missing ISOC OUT endpoint on interface config %d\n", - sc->sc_dev.dv_xname, sc->sc_config); - - return ENOENT; - } - -#ifdef DIAGNOSTIC - if (rd_size > MLEN) { - printf("%s: rd_size=%d exceeds MLEN\n", - sc->sc_dev.dv_xname, rd_size); - - return EOVERFLOW; - } - - if (wr_size > MLEN) { - printf("%s: wr_size=%d exceeds MLEN\n", - sc->sc_dev.dv_xname, wr_size); - - return EOVERFLOW; - } -#endif - - sc->sc_scord_size = rd_size; - sc->sc_scord_addr = rd_addr; - - sc->sc_scowr_size = wr_size; - sc->sc_scowr_addr = wr_addr; - - return 0; -} - -void -ubt_abortdealloc(struct ubt_softc *sc) -{ - int i; - - DPRINTFN(1, "sc=%p\n", sc); - - /* Abort all pipes */ - if (sc->sc_evt_pipe != NULL) { - usbd_abort_pipe(sc->sc_evt_pipe); - usbd_close_pipe(sc->sc_evt_pipe); - sc->sc_evt_pipe = NULL; - } - - if (sc->sc_aclrd_pipe != NULL) { - usbd_abort_pipe(sc->sc_aclrd_pipe); - usbd_close_pipe(sc->sc_aclrd_pipe); - sc->sc_aclrd_pipe = NULL; - } - - if (sc->sc_aclwr_pipe != NULL) { - usbd_abort_pipe(sc->sc_aclwr_pipe); - usbd_close_pipe(sc->sc_aclwr_pipe); - sc->sc_aclwr_pipe = NULL; - } - - if (sc->sc_scord_pipe != NULL) { - usbd_abort_pipe(sc->sc_scord_pipe); - usbd_close_pipe(sc->sc_scord_pipe); - sc->sc_scord_pipe = NULL; - } - - if (sc->sc_scowr_pipe != NULL) { - usbd_abort_pipe(sc->sc_scowr_pipe); - usbd_close_pipe(sc->sc_scowr_pipe); - sc->sc_scowr_pipe = NULL; - } - - /* Free event buffer */ - if (sc->sc_evt_buf != NULL) { - free(sc->sc_evt_buf, M_USBDEV); - sc->sc_evt_buf = NULL; - } - - /* Free all xfers and xfer buffers (implicit) */ - if (sc->sc_cmd_xfer != NULL) { - usbd_free_xfer(sc->sc_cmd_xfer); - sc->sc_cmd_xfer = NULL; - sc->sc_cmd_buf = NULL; - } - - if (sc->sc_aclrd_xfer != NULL) { - usbd_free_xfer(sc->sc_aclrd_xfer); - sc->sc_aclrd_xfer = NULL; - sc->sc_aclrd_buf = NULL; - } - - if (sc->sc_aclwr_xfer != NULL) { - usbd_free_xfer(sc->sc_aclwr_xfer); - sc->sc_aclwr_xfer = NULL; - sc->sc_aclwr_buf = NULL; - } - - for (i = 0 ; i < UBT_NXFERS ; i++) { - if (sc->sc_scord[i].xfer != NULL) { - usbd_free_xfer(sc->sc_scord[i].xfer); - sc->sc_scord[i].xfer = NULL; - sc->sc_scord[i].buf = NULL; - } - - if (sc->sc_scowr[i].xfer != NULL) { - usbd_free_xfer(sc->sc_scowr[i].xfer); - sc->sc_scowr[i].xfer = NULL; - sc->sc_scowr[i].buf = NULL; - } - } - - /* Free partial SCO packets */ - if (sc->sc_scord_mbuf != NULL) { - m_freem(sc->sc_scord_mbuf); - sc->sc_scord_mbuf = NULL; - } - - if (sc->sc_scowr_mbuf != NULL) { - m_freem(sc->sc_scowr_mbuf); - sc->sc_scowr_mbuf = NULL; - } - - /* Empty mbuf queues */ - IF_PURGE(&sc->sc_cmd_queue); - IF_PURGE(&sc->sc_aclwr_queue); - IF_PURGE(&sc->sc_scowr_queue); -} - -/******************************************************************************* - * - * Bluetooth Unit/USB callbacks - * - */ -int -ubt_enable(struct device *self) -{ - struct ubt_softc *sc = (struct ubt_softc *)self; - usbd_status err; - int s, i, error; - - DPRINTFN(1, "sc=%p\n", sc); - - if (sc->sc_enabled) - return 0; - - s = splusb(); - - /* Events */ - sc->sc_evt_buf = malloc(UBT_BUFSIZ_EVENT, M_USBDEV, M_NOWAIT); - if (sc->sc_evt_buf == NULL) { - error = ENOMEM; - goto bad; - } - err = usbd_open_pipe_intr(sc->sc_iface0, - sc->sc_evt_addr, - USBD_SHORT_XFER_OK, - &sc->sc_evt_pipe, - sc, - sc->sc_evt_buf, - UBT_BUFSIZ_EVENT, - ubt_recv_event, - USBD_DEFAULT_INTERVAL); - if (err != USBD_NORMAL_COMPLETION) { - error = EIO; - goto bad; - } - - /* Commands */ - sc->sc_cmd_xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_cmd_xfer == NULL) { - error = ENOMEM; - goto bad; - } - sc->sc_cmd_buf = usbd_alloc_buffer(sc->sc_cmd_xfer, UBT_BUFSIZ_CMD); - if (sc->sc_cmd_buf == NULL) { - error = ENOMEM; - goto bad; - } - sc->sc_cmd_busy = 0; - - /* ACL read */ - err = usbd_open_pipe(sc->sc_iface0, sc->sc_aclrd_addr, - USBD_EXCLUSIVE_USE, &sc->sc_aclrd_pipe); - if (err != USBD_NORMAL_COMPLETION) { - error = EIO; - goto bad; - } - sc->sc_aclrd_xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_aclrd_xfer == NULL) { - error = ENOMEM; - goto bad; - } - sc->sc_aclrd_buf = usbd_alloc_buffer(sc->sc_aclrd_xfer, UBT_BUFSIZ_ACL); - if (sc->sc_aclrd_buf == NULL) { - error = ENOMEM; - goto bad; - } - sc->sc_aclrd_busy = 0; - ubt_recv_acl_start(sc); - - /* ACL write */ - err = usbd_open_pipe(sc->sc_iface0, sc->sc_aclwr_addr, - USBD_EXCLUSIVE_USE, &sc->sc_aclwr_pipe); - if (err != USBD_NORMAL_COMPLETION) { - error = EIO; - goto bad; - } - sc->sc_aclwr_xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_aclwr_xfer == NULL) { - error = ENOMEM; - goto bad; - } - sc->sc_aclwr_buf = usbd_alloc_buffer(sc->sc_aclwr_xfer, UBT_BUFSIZ_ACL); - if (sc->sc_aclwr_buf == NULL) { - error = ENOMEM; - goto bad; - } - sc->sc_aclwr_busy = 0; - - /* SCO read */ - if (sc->sc_scord_size > 0) { - err = usbd_open_pipe(sc->sc_iface1, sc->sc_scord_addr, - USBD_EXCLUSIVE_USE, &sc->sc_scord_pipe); - if (err != USBD_NORMAL_COMPLETION) { - error = EIO; - goto bad; - } - - for (i = 0 ; i < UBT_NXFERS ; i++) { - sc->sc_scord[i].xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_scord[i].xfer == NULL) { - error = ENOMEM; - goto bad; - } - sc->sc_scord[i].buf = usbd_alloc_buffer(sc->sc_scord[i].xfer, - sc->sc_scord_size * UBT_NFRAMES); - if (sc->sc_scord[i].buf == NULL) { - error = ENOMEM; - goto bad; - } - sc->sc_scord[i].softc = sc; - sc->sc_scord[i].busy = 0; - ubt_recv_sco_start1(sc, &sc->sc_scord[i]); - } - } - - /* SCO write */ - if (sc->sc_scowr_size > 0) { - err = usbd_open_pipe(sc->sc_iface1, sc->sc_scowr_addr, - USBD_EXCLUSIVE_USE, &sc->sc_scowr_pipe); - if (err != USBD_NORMAL_COMPLETION) { - error = EIO; - goto bad; - } - - for (i = 0 ; i < UBT_NXFERS ; i++) { - sc->sc_scowr[i].xfer = usbd_alloc_xfer(sc->sc_udev); - if (sc->sc_scowr[i].xfer == NULL) { - error = ENOMEM; - goto bad; - } - sc->sc_scowr[i].buf = usbd_alloc_buffer(sc->sc_scowr[i].xfer, - sc->sc_scowr_size * UBT_NFRAMES); - if (sc->sc_scowr[i].buf == NULL) { - error = ENOMEM; - goto bad; - } - sc->sc_scowr[i].softc = sc; - sc->sc_scowr[i].busy = 0; - } - - sc->sc_scowr_busy = 0; - } - - sc->sc_enabled = 1; - splx(s); - return 0; - -bad: - ubt_abortdealloc(sc); - splx(s); - return error; -} - -void -ubt_disable(struct device *self) -{ - struct ubt_softc *sc = (struct ubt_softc *)self; - int s; - - DPRINTFN(1, "sc=%p\n", sc); - - if (sc->sc_enabled == 0) - return; - - s = splusb(); - ubt_abortdealloc(sc); - - sc->sc_enabled = 0; - splx(s); -} - -void -ubt_xmit_cmd(struct device *self, struct mbuf *m) -{ - struct ubt_softc *sc = (struct ubt_softc *)self; - int s; - - KASSERT(sc->sc_enabled); - - s = splusb(); - IF_ENQUEUE(&sc->sc_cmd_queue, m); - - if (sc->sc_cmd_busy == 0) - ubt_xmit_cmd_start(sc); - - splx(s); -} - -void -ubt_xmit_cmd_start(struct ubt_softc *sc) -{ - usb_device_request_t req; - usbd_status status; - struct mbuf *m; - int len; - - if (usbd_is_dying(sc->sc_udev)) - return; - - if (IF_IS_EMPTY(&sc->sc_cmd_queue)) - return; - - IF_DEQUEUE(&sc->sc_cmd_queue, m); - KASSERT(m != NULL); - - DPRINTFN(15, "%s: xmit CMD packet (%d bytes)\n", - &sc->sc_dev, m->m_pkthdr.len); - - sc->sc_refcnt++; - sc->sc_cmd_busy = 1; - - len = m->m_pkthdr.len - 1; - m_copydata(m, 1, len, sc->sc_cmd_buf); - m_freem(m); - - memset(&req, 0, sizeof(req)); - req.bmRequestType = UT_WRITE_CLASS_DEVICE; - USETW(req.wLength, len); - - usbd_setup_default_xfer(sc->sc_cmd_xfer, - sc->sc_udev, - sc, - UBT_CMD_TIMEOUT, - &req, - sc->sc_cmd_buf, - len, - USBD_NO_COPY | USBD_FORCE_SHORT_XFER, - ubt_xmit_cmd_complete); - - status = usbd_transfer(sc->sc_cmd_xfer); - - KASSERT(status != USBD_NORMAL_COMPLETION); - - if (status != USBD_IN_PROGRESS) { - DPRINTF("usbd_transfer status=%s (%d)\n", - usbd_errstr(status), status); - - sc->sc_refcnt--; - sc->sc_cmd_busy = 0; - } -} - -void -ubt_xmit_cmd_complete(struct usbd_xfer *xfer, void *h, usbd_status status) -{ - struct ubt_softc *sc = h; - uint32_t count; - - DPRINTFN(15, "%s: CMD complete status=%s (%d)\n", - sc->sc_dev.dv_xname, usbd_errstr(status), status); - - sc->sc_cmd_busy = 0; - - if (--sc->sc_refcnt < 0) { - DPRINTF("sc_refcnt=%d\n", sc->sc_refcnt); - usb_detach_wakeup(&sc->sc_dev); - return; - } - - if (usbd_is_dying(sc->sc_udev)) { - DPRINTF("dying\n"); - return; - } - - if (status != USBD_NORMAL_COMPLETION) { - DPRINTF("status=%s (%d)\n", - usbd_errstr(status), status); - - sc->sc_stats.err_tx++; - return; - } - - usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL); - sc->sc_stats.cmd_tx++; - sc->sc_stats.byte_tx += count; - - ubt_xmit_cmd_start(sc); -} - -void -ubt_xmit_acl(struct device *self, struct mbuf *m) -{ - struct ubt_softc *sc = (struct ubt_softc *)self; - int s; - - KASSERT(sc->sc_enabled); - - s = splusb(); - IF_ENQUEUE(&sc->sc_aclwr_queue, m); - - if (sc->sc_aclwr_busy == 0) - ubt_xmit_acl_start(sc); - - splx(s); -} - -void -ubt_xmit_acl_start(struct ubt_softc *sc) -{ - struct mbuf *m; - usbd_status status; - int len; - - if (usbd_is_dying(sc->sc_udev)) - return; - - if (IF_IS_EMPTY(&sc->sc_aclwr_queue)) - return; - - sc->sc_refcnt++; - sc->sc_aclwr_busy = 1; - - IF_DEQUEUE(&sc->sc_aclwr_queue, m); - KASSERT(m != NULL); - - DPRINTFN(15, "%s: xmit ACL packet (%d bytes)\n", - sc->sc_dev.dv_xname, m->m_pkthdr.len); - - len = m->m_pkthdr.len - 1; - if (len > UBT_BUFSIZ_ACL) { - DPRINTF("%s: truncating ACL packet (%d => %d)!\n", - sc->sc_dev.dv_xname, len, UBT_BUFSIZ_ACL); - - len = UBT_BUFSIZ_ACL; - } - - m_copydata(m, 1, len, sc->sc_aclwr_buf); - m_freem(m); - - sc->sc_stats.acl_tx++; - sc->sc_stats.byte_tx += len; - - usbd_setup_xfer(sc->sc_aclwr_xfer, - sc->sc_aclwr_pipe, - sc, - sc->sc_aclwr_buf, - len, - USBD_NO_COPY | USBD_FORCE_SHORT_XFER, - UBT_ACL_TIMEOUT, - ubt_xmit_acl_complete); - - status = usbd_transfer(sc->sc_aclwr_xfer); - - KASSERT(status != USBD_NORMAL_COMPLETION); - - if (status != USBD_IN_PROGRESS) { - DPRINTF("usbd_transfer status=%s (%d)\n", - usbd_errstr(status), status); - - sc->sc_refcnt--; - sc->sc_aclwr_busy = 0; - } -} - -void -ubt_xmit_acl_complete(struct usbd_xfer *xfer, void *h, usbd_status status) -{ - struct ubt_softc *sc = h; - - DPRINTFN(15, "%s: ACL complete status=%s (%d)\n", - sc->sc_dev.dv_xname, usbd_errstr(status), status); - - sc->sc_aclwr_busy = 0; - - if (--sc->sc_refcnt < 0) { - usb_detach_wakeup(&sc->sc_dev); - return; - } - - if (usbd_is_dying(sc->sc_udev)) - return; - - if (status != USBD_NORMAL_COMPLETION) { - DPRINTF("status=%s (%d)\n", - usbd_errstr(status), status); - - sc->sc_stats.err_tx++; - - if (status == USBD_STALLED) - usbd_clear_endpoint_stall_async(sc->sc_aclwr_pipe); - else - return; - } - - ubt_xmit_acl_start(sc); -} - -void -ubt_xmit_sco(struct device *self, struct mbuf *m) -{ - struct ubt_softc *sc = (struct ubt_softc *)self; - int s; - - KASSERT(sc->sc_enabled); - - s = splusb(); - IF_ENQUEUE(&sc->sc_scowr_queue, m); - - if (sc->sc_scowr_busy == 0) - ubt_xmit_sco_start(sc); - - splx(s); -} - -void -ubt_xmit_sco_start(struct ubt_softc *sc) -{ - int i; - - if (usbd_is_dying(sc->sc_udev) || sc->sc_scowr_size == 0) - return; - - for (i = 0 ; i < UBT_NXFERS ; i++) { - if (sc->sc_scowr[i].busy) - continue; - - ubt_xmit_sco_start1(sc, &sc->sc_scowr[i]); - } -} - -void -ubt_xmit_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc) -{ - struct mbuf *m; - uint8_t *buf; - int num, len, size, space; - - space = sc->sc_scowr_size * UBT_NFRAMES; - buf = isoc->buf; - len = 0; - - /* - * Fill the request buffer with data from the queue, - * keeping any leftover packet on our private hook. - * - * Complete packets are passed back up to the stack - * for disposal, since we can't rely on the controller - * to tell us when it has finished with them. - */ - - m = sc->sc_scowr_mbuf; - while (space > 0) { - if (m == NULL) { - IF_DEQUEUE(&sc->sc_scowr_queue, m); - if (m == NULL) - break; - - m_adj(m, 1); /* packet type */ - } - - if (m->m_pkthdr.len > 0) { - size = MIN(m->m_pkthdr.len, space); - - m_copydata(m, 0, size, buf); - m_adj(m, size); - - buf += size; - len += size; - space -= size; - } - - if (m->m_pkthdr.len == 0) { - sc->sc_stats.sco_tx++; - if (!hci_complete_sco(sc->sc_unit, m)) - sc->sc_stats.err_tx++; - - m = NULL; - } - } - sc->sc_scowr_mbuf = m; - - DPRINTFN(15, "isoc=%p, len=%d, space=%d\n", isoc, len, space); - - if (len == 0) /* nothing to send */ - return; - - sc->sc_refcnt++; - sc->sc_scowr_busy = 1; - sc->sc_stats.byte_tx += len; - isoc->busy = 1; - - /* - * calculate number of isoc frames and sizes - */ - - for (num = 0 ; len > 0 ; num++) { - size = MIN(sc->sc_scowr_size, len); - - isoc->size[num] = size; - len -= size; - } - - usbd_setup_isoc_xfer(isoc->xfer, - sc->sc_scowr_pipe, - isoc, - isoc->size, - num, - USBD_NO_COPY | USBD_FORCE_SHORT_XFER, - ubt_xmit_sco_complete); - - usbd_transfer(isoc->xfer); -} - -void -ubt_xmit_sco_complete(struct usbd_xfer *xfer, void *h, usbd_status status) -{ - struct ubt_isoc_xfer *isoc = h; - struct ubt_softc *sc; - int i; - - KASSERT(xfer == isoc->xfer); - sc = isoc->softc; - - DPRINTFN(15, "isoc=%p, status=%s (%d)\n", - isoc, usbd_errstr(status), status); - - isoc->busy = 0; - - for (i = 0 ; ; i++) { - if (i == UBT_NXFERS) { - sc->sc_scowr_busy = 0; - break; - } - - if (sc->sc_scowr[i].busy) - break; - } - - if (--sc->sc_refcnt < 0) { - usb_detach_wakeup(&sc->sc_dev); - return; - } - - if (usbd_is_dying(sc->sc_udev)) - return; - - if (status != USBD_NORMAL_COMPLETION) { - DPRINTF("status=%s (%d)\n", - usbd_errstr(status), status); - - sc->sc_stats.err_tx++; - - if (status == USBD_STALLED) - usbd_clear_endpoint_stall_async(sc->sc_scowr_pipe); - else - return; - } - - ubt_xmit_sco_start(sc); -} - -/* - * load incoming data into an mbuf with - * leading type byte - */ -static struct mbuf * -ubt_mbufload(uint8_t *buf, int count, uint8_t type) -{ - struct mbuf *m; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return NULL; - - *mtod(m, uint8_t *) = type; - m->m_pkthdr.len = m->m_len = MHLEN; - m_copyback(m, 1, count, buf, M_NOWAIT); /* extends if this doesn't fail */ - if (m->m_pkthdr.len != MAX(MHLEN, count + 1)) { - m_free(m); - return NULL; - } - - m->m_pkthdr.len = count + 1; - m->m_len = MIN(MHLEN, m->m_pkthdr.len); - - return m; -} - -void -ubt_recv_event(struct usbd_xfer *xfer, void *h, usbd_status status) -{ - struct ubt_softc *sc = h; - struct mbuf *m; - uint32_t count; - void *buf; - - DPRINTFN(15, "sc=%p status=%s (%d)\n", - sc, usbd_errstr(status), status); - - if (status != USBD_NORMAL_COMPLETION || usbd_is_dying(sc->sc_udev)) - return; - - usbd_get_xfer_status(xfer, NULL, &buf, &count, NULL); - - if (count < sizeof(hci_event_hdr_t) - 1) { - DPRINTF("dumped undersized event (count = %d)\n", count); - sc->sc_stats.err_rx++; - return; - } - - sc->sc_stats.evt_rx++; - sc->sc_stats.byte_rx += count; - - m = ubt_mbufload(buf, count, HCI_EVENT_PKT); - if (m == NULL || !hci_input_event(sc->sc_unit, m)) - sc->sc_stats.err_rx++; -} - -void -ubt_recv_acl_start(struct ubt_softc *sc) -{ - usbd_status status; - - DPRINTFN(15, "sc=%p\n", sc); - - if (sc->sc_aclrd_busy) { - DPRINTF("sc_aclrd_busy=%d\n", sc->sc_aclrd_busy); - return; - } - if (usbd_is_dying(sc->sc_udev)) { - DPRINTF("dying"); - return; - } - - sc->sc_refcnt++; - sc->sc_aclrd_busy = 1; - - usbd_setup_xfer(sc->sc_aclrd_xfer, - sc->sc_aclrd_pipe, - sc, - sc->sc_aclrd_buf, - UBT_BUFSIZ_ACL, - USBD_NO_COPY | USBD_SHORT_XFER_OK, - USBD_NO_TIMEOUT, - ubt_recv_acl_complete); - - status = usbd_transfer(sc->sc_aclrd_xfer); - - KASSERT(status != USBD_NORMAL_COMPLETION); - - if (status != USBD_IN_PROGRESS) { - DPRINTF("usbd_transfer status=%s (%d)\n", - usbd_errstr(status), status); - - sc->sc_refcnt--; - sc->sc_aclrd_busy = 0; - } -} - -void -ubt_recv_acl_complete(struct usbd_xfer *xfer, void *h, usbd_status status) -{ - struct ubt_softc *sc = h; - struct mbuf *m; - uint32_t count; - void *buf; - - DPRINTFN(15, "sc=%p status=%s (%d)\n", - sc, usbd_errstr(status), status); - - sc->sc_aclrd_busy = 0; - - if (--sc->sc_refcnt < 0) { - DPRINTF("refcnt = %d\n", sc->sc_refcnt); - usb_detach_wakeup(&sc->sc_dev); - return; - } - - if (usbd_is_dying(sc->sc_udev)) { - DPRINTF("dying\n"); - return; - } - - if (status != USBD_NORMAL_COMPLETION) { - DPRINTF("status=%s (%d)\n", - usbd_errstr(status), status); - - sc->sc_stats.err_rx++; - - if (status == USBD_STALLED) - usbd_clear_endpoint_stall_async(sc->sc_aclrd_pipe); - else - return; - } else { - usbd_get_xfer_status(xfer, NULL, &buf, &count, NULL); - - if (count < sizeof(hci_acldata_hdr_t) - 1) { - DPRINTF("dumped undersized packet (%d)\n", count); - sc->sc_stats.err_rx++; - } else { - sc->sc_stats.acl_rx++; - sc->sc_stats.byte_rx += count; - - m = ubt_mbufload(buf, count, HCI_ACL_DATA_PKT); - if (m == NULL || !hci_input_acl(sc->sc_unit, m)) - sc->sc_stats.err_rx++; - } - } - - /* and restart */ - ubt_recv_acl_start(sc); -} - -void -ubt_recv_sco_start1(struct ubt_softc *sc, struct ubt_isoc_xfer *isoc) -{ - int i; - - DPRINTFN(15, "sc=%p, isoc=%p\n", sc, isoc); - - if (usbd_is_dying(sc->sc_udev)) { - DPRINTF("dying"); - return; - } - if (isoc->busy || sc->sc_scord_size == 0) { - DPRINTF("%s%s\n", - isoc->busy ? " busy" : "", - sc->sc_scord_size == 0 ? " size=0" : ""); - - return; - } - - sc->sc_refcnt++; - isoc->busy = 1; - - for (i = 0 ; i < UBT_NFRAMES ; i++) - isoc->size[i] = sc->sc_scord_size; - - usbd_setup_isoc_xfer(isoc->xfer, - sc->sc_scord_pipe, - isoc, - isoc->size, - UBT_NFRAMES, - USBD_NO_COPY | USBD_SHORT_XFER_OK, - ubt_recv_sco_complete); - - usbd_transfer(isoc->xfer); -} - -void -ubt_recv_sco_complete(struct usbd_xfer *xfer, void *h, usbd_status status) -{ - struct ubt_isoc_xfer *isoc = h; - struct ubt_softc *sc; - struct mbuf *m; - uint32_t count; - uint8_t *ptr, *frame; - int i, size, got, want; - - KASSERT(isoc != NULL); - KASSERT(isoc->xfer == xfer); - - sc = isoc->softc; - isoc->busy = 0; - - if (--sc->sc_refcnt < 0) { - DPRINTF("refcnt=%d\n", sc->sc_refcnt); - usb_detach_wakeup(&sc->sc_dev); - return; - } - - if (usbd_is_dying(sc->sc_udev)) { - DPRINTF("dying\n"); - return; - } - - if (status != USBD_NORMAL_COMPLETION) { - DPRINTF("status=%s (%d)\n", - usbd_errstr(status), status); - - sc->sc_stats.err_rx++; - - if (status == USBD_STALLED) { - usbd_clear_endpoint_stall_async(sc->sc_scord_pipe); - goto restart; - } - - return; - } - - usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL); - if (count == 0) - goto restart; - - DPRINTFN(15, "sc=%p, isoc=%p, count=%u\n", - sc, isoc, count); - - sc->sc_stats.byte_rx += count; - - /* - * Extract SCO packets from ISOC frames. The way we have it, - * no SCO packet can be bigger than MHLEN. This is unlikely - * to actually happen, but if we ran out of mbufs and lost - * sync then we may get spurious data that makes it seem that - * way, so we discard data that wont fit. This doesnt really - * help with the lost sync situation alas. - */ - - m = sc->sc_scord_mbuf; - if (m != NULL) { - sc->sc_scord_mbuf = NULL; - ptr = mtod(m, uint8_t *) + m->m_pkthdr.len; - got = m->m_pkthdr.len; - want = sizeof(hci_scodata_hdr_t); - if (got >= want) - want += mtod(m, hci_scodata_hdr_t *)->length ; - } else { - ptr = NULL; - got = 0; - want = 0; - } - - for (i = 0 ; i < UBT_NFRAMES ; i++) { - frame = isoc->buf + (i * sc->sc_scord_size); - - while (isoc->size[i] > 0) { - size = isoc->size[i]; - - if (m == NULL) { - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) { - printf("%s: out of memory (xfer halted)\n", - sc->sc_dev.dv_xname); - - sc->sc_stats.err_rx++; - return; /* lost sync */ - } - - ptr = mtod(m, uint8_t *); - *ptr++ = HCI_SCO_DATA_PKT; - got = 1; - want = sizeof(hci_scodata_hdr_t); - } - - if (got + size > want) - size = want - got; - - if (got + size > MHLEN) - memcpy(ptr, frame, MHLEN - got); - else - memcpy(ptr, frame, size); - - ptr += size; - got += size; - frame += size; - - if (got == want) { - /* - * If we only got a header, add the packet - * length to our want count. Send complete - * packets up to protocol stack. - */ - if (want == sizeof(hci_scodata_hdr_t)) - want += mtod(m, hci_scodata_hdr_t *)->length; - - if (got == want) { - m->m_pkthdr.len = m->m_len = got; - sc->sc_stats.sco_rx++; - if (!hci_input_sco(sc->sc_unit, m)) - sc->sc_stats.err_rx++; - - m = NULL; - } - } - - isoc->size[i] -= size; - } - } - - if (m != NULL) { - m->m_pkthdr.len = m->m_len = got; - sc->sc_scord_mbuf = m; - } - -restart: /* and restart */ - ubt_recv_sco_start1(sc, isoc); -} - -void -ubt_stats(struct device *self, struct bt_stats *dest, int flush) -{ - struct ubt_softc *sc = (struct ubt_softc *)self; - int s; - - s = splusb(); - memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats)); - - if (flush) - memset(&sc->sc_stats, 0, sizeof(struct bt_stats)); - - splx(s); -} diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c index f34e03d6baf..67cbc10a424 100644 --- a/sys/kern/uipc_domain.c +++ b/sys/kern/uipc_domain.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_domain.c,v 1.36 2014/07/08 17:19:25 deraadt Exp $ */ +/* $OpenBSD: uipc_domain.c,v 1.37 2014/07/11 21:54:38 tedu Exp $ */ /* $NetBSD: uipc_domain.c,v 1.14 1996/02/09 19:00:44 christos Exp $ */ /* @@ -44,7 +44,6 @@ #include <sys/sysctl.h> #include <sys/timeout.h> -#include "bluetooth.h" #include "bpfilter.h" #include "pflow.h" @@ -95,9 +94,6 @@ domaininit(void) ADDDOMAIN(key); #endif #endif -#if NBLUETOOTH > 0 - ADDDOMAIN(bt); -#endif ADDDOMAIN(route); for (dp = domains; dp; dp = dp->dom_next) { diff --git a/sys/net/if.c b/sys/net/if.c index 86f0b35d513..1d5a1b24a1c 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.294 2014/07/08 07:10:12 dlg Exp $ */ +/* $OpenBSD: if.c,v 1.295 2014/07/11 21:54:38 tedu Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -61,7 +61,6 @@ * @(#)if.c 8.3 (Berkeley) 1/4/94 */ -#include "bluetooth.h" #include "bpfilter.h" #include "bridge.h" #include "carp.h" diff --git a/sys/net/netisr.c b/sys/net/netisr.c index bc0310fb347..7093418194a 100644 --- a/sys/net/netisr.c +++ b/sys/net/netisr.c @@ -20,7 +20,6 @@ #include <machine/intr.h> -#include "bluetooth.h" #include "ether.h" #include "ppp.h" #include "bridge.h" @@ -68,11 +67,6 @@ netintr(void *unused) /* ARGSUSED */ if (n & (1 << NETISR_PPPOE)) pppoeintr(); #endif -#if NBLUETOOTH > 0 - if (n & (1 << NETISR_BT)) - btintr(); -#endif - t |= n; } diff --git a/sys/netbt/bluetooth.h b/sys/netbt/bluetooth.h deleted file mode 100644 index 027a08fee09..00000000000 --- a/sys/netbt/bluetooth.h +++ /dev/null @@ -1,167 +0,0 @@ -/* $OpenBSD: bluetooth.h,v 1.6 2008/11/22 04:42:58 uwe Exp $ */ -/* $NetBSD: bluetooth.h,v 1.8 2008/09/08 23:36:55 gmcgarry Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _NETBT_BLUETOOTH_H_ -#define _NETBT_BLUETOOTH_H_ - -#include <sys/socket.h> -#include <sys/types.h> - -/* - * Bluetooth Address Family Protocol Numbers - */ -#define BTPROTO_HCI 1 -#define BTPROTO_L2CAP 2 -#define BTPROTO_RFCOMM 3 -#define BTPROTO_SCO 4 - -/* All sizes are in bytes */ -#define BLUETOOTH_BDADDR_SIZE 6 - -/* - * Bluetooth device address - */ -typedef struct { - uint8_t b[BLUETOOTH_BDADDR_SIZE]; -} __packed bdaddr_t; - -/* - * bdaddr utility functions - */ -static __inline int -bdaddr_same(const bdaddr_t *a, const bdaddr_t *b) -{ - - return (a->b[0] == b->b[0] && a->b[1] == b->b[1] - && a->b[2] == b->b[2] && a->b[3] == b->b[3] - && a->b[4] == b->b[4] && a->b[5] == b->b[5]); -} - -static __inline int -bdaddr_any(const bdaddr_t *a) -{ - - return (a->b[0] == 0 && a->b[1] == 0 && a->b[2] == 0 - && a->b[3] == 0 && a->b[4] == 0 && a->b[5] == 0); -} - -static __inline void -bdaddr_copy(bdaddr_t *d, const bdaddr_t *s) -{ - - d->b[0] = s->b[0]; - d->b[1] = s->b[1]; - d->b[2] = s->b[2]; - d->b[3] = s->b[3]; - d->b[4] = s->b[4]; - d->b[5] = s->b[5]; -} - -/* - * Socket address used by Bluetooth protocols - */ -struct sockaddr_bt { - uint8_t bt_len; - sa_family_t bt_family; - bdaddr_t bt_bdaddr; - uint16_t bt_psm; - uint8_t bt_channel; - uint8_t bt_zero[5]; -}; - -/* Note: this is actually 6 bytes including terminator */ -#define BDADDR_ANY ((const bdaddr_t *) "\000\000\000\000\000") - -#ifdef _KERNEL - -/* - * Bluetooth Protocol API callback methods - */ -struct mbuf; -struct btproto { - void (*connecting)(void *); - void (*connected)(void *); - void (*disconnected)(void *, int); - void *(*newconn)(void *, struct sockaddr_bt *, struct sockaddr_bt *); - void (*complete)(void *, int); - void (*linkmode)(void *, int); - void (*input)(void *, struct mbuf *); -}; - -/* - * Debugging stuff - */ - -#define BLUETOOTH_DEBUG -#ifdef BLUETOOTH_DEBUG -extern int bluetooth_debug; -# define DPRINTF(fmt, args...) do { \ - if (bluetooth_debug) \ - printf("%s: "fmt, __func__ , ##args); \ -} while (/* CONSTCOND */0) - -# define DPRINTFN(n, fmt, args...) do { \ - if (bluetooth_debug > (n)) \ - printf("%s: "fmt, __func__ , ##args); \ -} while (/* CONSTCOND */0) - -# define UNKNOWN(value) \ - printf("%s: %s = %d unknown!\n", __func__, #value, (value)); -#else -# define DPRINTF(...) ((void)0) -# define DPRINTFN(...) ((void)0) -# define UNKNOWN(x) ((void)0) -#endif /* BLUETOOTH_DEBUG */ - -extern struct mutex bt_lock; - -/* XXX NetBSD compatibility goo, abused for debugging */ -#ifdef BLUETOOTH_DEBUG -#define mutex_enter(mtx) do { \ - DPRINTFN(1, "mtx_enter(" __STRING(mtx) ") in %d\n", \ - curproc ? curproc->p_pid : 0); \ - mtx_enter((mtx)); \ -} while (/*CONSTCOND*/0) -#define mutex_exit(mtx) do { \ - DPRINTFN(1, "mtx_leave(" __STRING(mtx) ") in %d\n", \ - curproc ? curproc->p_pid : 0); \ - mtx_leave((mtx)); \ -} while (/*CONSTCOND*/0) -#else -#define mutex_enter mtx_enter -#define mutex_exit mtx_leave -#endif - -#endif /* _KERNEL */ - -#endif /* _NETBT_BLUETOOTH_H_ */ diff --git a/sys/netbt/bt_input.c b/sys/netbt/bt_input.c deleted file mode 100644 index 61976fbebb4..00000000000 --- a/sys/netbt/bt_input.c +++ /dev/null @@ -1,34 +0,0 @@ -/* $OpenBSD: bt_input.c,v 1.5 2007/06/24 20:55:27 uwe Exp $ */ -/* - * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/timeout.h> - -#include <net/netisr.h> - -#include <netbt/hci.h> - -void -btintr(void) -{ - struct hci_unit *unit; - - TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { - hci_intr(unit); - } -} diff --git a/sys/netbt/bt_proto.c b/sys/netbt/bt_proto.c deleted file mode 100644 index a291753d213..00000000000 --- a/sys/netbt/bt_proto.c +++ /dev/null @@ -1,86 +0,0 @@ -/* $OpenBSD: bt_proto.c,v 1.6 2008/11/24 20:19:51 uwe Exp $ */ -/* - * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/param.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/timeout.h> - -#include <netbt/bluetooth.h> -#include <netbt/bt_var.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> -#include <netbt/rfcomm.h> -#include <netbt/sco.h> - -struct domain btdomain; - -void bt_init(void); - -struct protosw btsw[] = { - { SOCK_RAW, &btdomain, BTPROTO_HCI, - PR_ATOMIC | PR_ADDR, - NULL/*input*/, NULL/*output*/, NULL/*ctlinput*/, - hci_ctloutput, hci_usrreq, NULL/*init*/, - NULL/*fasttimo*/, NULL/*slowtimo*/, NULL/*drain*/, - NULL/*sysctl*/ - }, - { SOCK_SEQPACKET, &btdomain, BTPROTO_SCO, - PR_ATOMIC | PR_CONNREQUIRED, - NULL/*input*/, NULL/*output*/, NULL/*ctlinput*/, - sco_ctloutput, sco_usrreq, NULL/*init*/, - NULL/*fasttimo*/, NULL/*slowtimo*/, NULL/*drain*/, - NULL/*sysctl*/ - }, - { SOCK_SEQPACKET, &btdomain, BTPROTO_L2CAP, - PR_ATOMIC | PR_CONNREQUIRED, - NULL/*input*/, NULL/*output*/, NULL/*ctlinput*/, - l2cap_ctloutput, l2cap_usrreq, l2cap_init, - NULL/*fasttimo*/, NULL/*slowtimo*/, NULL/*drain*/, - NULL/*sysctl*/ - }, - { SOCK_STREAM, &btdomain, BTPROTO_RFCOMM, - PR_CONNREQUIRED | PR_WANTRCVD, - NULL/*input*/, NULL/*output*/, NULL/*ctlinput*/, - rfcomm_ctloutput, rfcomm_usrreq, rfcomm_init, - NULL/*fasttimo*/, NULL/*slowtimo*/, NULL/*drain*/, - NULL/*sysctl*/ - } -}; - -struct domain btdomain = { - AF_BLUETOOTH, "bluetooth", - bt_init, NULL/*externalize*/, NULL/*dispose*/, - btsw, &btsw[sizeof(btsw) / sizeof(btsw[0])], NULL, - NULL/*rtattach*/, 32, sizeof(struct sockaddr_bt), - NULL/*ifattach*/, NULL/*ifdetach*/ -}; - -struct mutex bt_lock; - -void -bt_init(void) -{ - /* - * In accordance with mutex(9), since hci_intr() uses the - * lock, we associate the subsystem lock with IPL_SOFTNET. - * For unknown reasons, in NetBSD the interrupt level is - * IPL_NONE. - */ - mtx_init(&bt_lock, IPL_BIO); -} diff --git a/sys/netbt/bt_var.h b/sys/netbt/bt_var.h deleted file mode 100644 index 6d9ecb5ea18..00000000000 --- a/sys/netbt/bt_var.h +++ /dev/null @@ -1,21 +0,0 @@ -/* $OpenBSD: bt_var.h,v 1.2 2007/06/24 20:55:27 uwe Exp $ */ -/* - * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _NETBT_BT_VAR_H_ -#define _NETBT_BT_VAR_H_ - -#endif /* !_NETBT_BT_VAR_H_ */ diff --git a/sys/netbt/hci.h b/sys/netbt/hci.h deleted file mode 100644 index e9092e33bc1..00000000000 --- a/sys/netbt/hci.h +++ /dev/null @@ -1,2582 +0,0 @@ -/* $OpenBSD: hci.h,v 1.13 2008/11/25 14:00:12 uwe Exp $ */ -/* $NetBSD: hci.h,v 1.28 2008/09/08 23:36:55 gmcgarry Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/*- - * Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: hci.h,v 1.13 2008/11/25 14:00:12 uwe Exp $ - * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_hci.h,v 1.6 2005/01/07 01:45:43 imp Exp $ - */ - -/* - * This file contains everything that applications need to know from - * Host Controller Interface (HCI). Information taken from Bluetooth - * Core Specifications (v1.1, v2.0 and v2.1) - * - * This file can be included by both kernel and userland applications. - * - * NOTE: Here and after Bluetooth device is called a "unit". Bluetooth - * specification refers to both devices and units. They are the - * same thing (I think), so to be consistent word "unit" will be - * used. - */ - -#ifndef _NETBT_HCI_H_ -#define _NETBT_HCI_H_ - -#include <netbt/bluetooth.h> - -#include <sys/mutex.h> - -/************************************************************************** - ************************************************************************** - ** Common defines and types (HCI) - ************************************************************************** - **************************************************************************/ - -#define HCI_LAP_SIZE 3 /* unit LAP */ -#define HCI_KEY_SIZE 16 /* link key */ -#define HCI_PIN_SIZE 16 /* link PIN */ -#define HCI_EVENT_MASK_SIZE 8 /* event mask */ -#define HCI_CLASS_SIZE 3 /* unit class */ -#define HCI_FEATURES_SIZE 8 /* LMP features */ -#define HCI_UNIT_NAME_SIZE 248 /* unit name size */ -#define HCI_DEVNAME_SIZE 16 /* same as dv_xname */ -#define HCI_COMMANDS_SIZE 64 /* supported commands mask */ - -/* HCI specification */ -#define HCI_SPEC_V10 0x00 /* v1.0 */ -#define HCI_SPEC_V11 0x01 /* v1.1 */ -#define HCI_SPEC_V12 0x02 /* v1.2 */ -#define HCI_SPEC_V20 0x03 /* v2.0 */ -#define HCI_SPEC_V21 0x04 /* v2.1 */ -/* 0x05 - 0xFF - reserved for future use */ - -/* LMP features (and page 0 of extended features) */ -/* ------------------- byte 0 --------------------*/ -#define HCI_LMP_3SLOT 0x01 -#define HCI_LMP_5SLOT 0x02 -#define HCI_LMP_ENCRYPTION 0x04 -#define HCI_LMP_SLOT_OFFSET 0x08 -#define HCI_LMP_TIMIACCURACY 0x10 -#define HCI_LMP_ROLE_SWITCH 0x20 -#define HCI_LMP_HOLD_MODE 0x40 -#define HCI_LMP_SNIFF_MODE 0x80 -/* ------------------- byte 1 --------------------*/ -#define HCI_LMP_PARK_MODE 0x01 -#define HCI_LMP_RSSI 0x02 -#define HCI_LMP_CHANNEL_QUALITY 0x04 -#define HCI_LMP_SCO_LINK 0x08 -#define HCI_LMP_HV2_PKT 0x10 -#define HCI_LMP_HV3_PKT 0x20 -#define HCI_LMP_ULAW_LOG 0x40 -#define HCI_LMP_ALAW_LOG 0x80 -/* ------------------- byte 2 --------------------*/ -#define HCI_LMP_CVSD 0x01 -#define HCI_LMP_PAGISCHEME 0x02 -#define HCI_LMP_POWER_CONTROL 0x04 -#define HCI_LMP_TRANSPARENT_SCO 0x08 -#define HCI_LMP_FLOW_CONTROL_LAG0 0x10 -#define HCI_LMP_FLOW_CONTROL_LAG1 0x20 -#define HCI_LMP_FLOW_CONTROL_LAG2 0x40 -#define HCI_LMP_BC_ENCRYPTION 0x80 -/* ------------------- byte 3 --------------------*/ -/* reserved 0x01 */ -#define HCI_LMP_EDR_ACL_2MBPS 0x02 -#define HCI_LMP_EDR_ACL_3MBPS 0x04 -#define HCI_LMP_ENHANCED_ISCAN 0x08 -#define HCI_LMP_INTERLACED_ISCAN 0x10 -#define HCI_LMP_INTERLACED_PSCAN 0x20 -#define HCI_LMP_RSSI_INQUIRY 0x40 -#define HCI_LMP_EV3_PKT 0x80 -/* ------------------- byte 4 --------------------*/ -#define HCI_LMP_EV4_PKT 0x01 -#define HCI_LMP_EV5_PKT 0x02 -/* reserved 0x04 */ -#define HCI_LMP_AFH_CAPABLE_SLAVE 0x08 -#define HCI_LMP_AFH_CLASS_SLAVE 0x10 -/* reserved 0x20 */ -/* reserved 0x40 */ -#define HCI_LMP_3SLOT_EDR_ACL 0x80 -/* ------------------- byte 5 --------------------*/ -#define HCI_LMP_5SLOT_EDR_ACL 0x01 -#define HCI_LMP_SNIFF_SUBRATING 0x02 -#define HCI_LMP_PAUSE_ENCRYPTION 0x04 -#define HCI_LMP_AFH_CAPABLE_MASTER 0x08 -#define HCI_LMP_AFH_CLASS_MASTER 0x10 -#define HCI_LMP_EDR_eSCO_2MBPS 0x20 -#define HCI_LMP_EDR_eSCO_3MBPS 0x40 -#define HCI_LMP_3SLOT_EDR_eSCO 0x80 -/* ------------------- byte 6 --------------------*/ -#define HCI_LMP_EXTENDED_INQUIRY 0x01 -/* reserved 0x02 */ -/* reserved 0x04 */ -#define HCI_LMP_SIMPLE_PAIRING 0x08 -#define HCI_LMP_ENCAPSULATED_PDU 0x10 -#define HCI_LMP_ERRDATA_REPORTING 0x20 -#define HCI_LMP_NOFLUSH_PB_FLAG 0x40 -/* reserved 0x80 */ -/* ------------------- byte 7 --------------------*/ -#define HCI_LMP_LINK_SUPERVISION_TO 0x01 -#define HCI_LMP_INQ_RSP_TX_POWER 0x02 -#define HCI_LMP_EXTENDED_FEATURES 0x80 - -/* Link types */ -#define HCI_LINK_SCO 0x00 /* Voice */ -#define HCI_LINK_ACL 0x01 /* Data */ -#define HCI_LINK_eSCO 0x02 /* eSCO */ -/* 0x03 - 0xFF - reserved for future use */ - -/* - * ACL/SCO packet type bits are set to enable the - * packet type, except for 2MBPS and 3MBPS when they - * are unset to enable the packet type. - */ -/* ACL Packet types for "Create Connection" */ -#define HCI_PKT_2MBPS_DH1 0x0002 -#define HCI_PKT_3MBPS_DH1 0x0004 -#define HCI_PKT_DM1 0x0008 -#define HCI_PKT_DH1 0x0010 -#define HCI_PKT_2MBPS_DH3 0x0100 -#define HCI_PKT_3MBPS_DH3 0x0200 -#define HCI_PKT_DM3 0x0400 -#define HCI_PKT_DH3 0x0800 -#define HCI_PKT_2MBPS_DH5 0x1000 -#define HCI_PKT_3MBPS_DH5 0x2000 -#define HCI_PKT_DM5 0x4000 -#define HCI_PKT_DH5 0x8000 - -/* SCO Packet types for "Setup Synchronous Connection" */ -#define HCI_PKT_HV1 0x0001 -#define HCI_PKT_HV2 0x0002 -#define HCI_PKT_HV3 0x0004 -#define HCI_PKT_EV3 0x0008 -#define HCI_PKT_EV4 0x0010 -#define HCI_PKT_EV5 0x0020 -#define HCI_PKT_2MBPS_EV3 0x0040 -#define HCI_PKT_3MBPS_EV3 0x0080 -#define HCI_PKT_2MBPS_EV5 0x0100 -#define HCI_PKT_3MBPS_EV5 0x0200 - -/* - * Connection modes/Unit modes - * - * This is confusing. It means that one of the units change its mode - * for the specific connection. For example one connection was put on - * hold (but i could be wrong :) - */ - -/* Page scan modes (are deprecated) */ -#define HCI_MANDATORY_PAGE_SCAN_MODE 0x00 -#define HCI_OPTIONAL_PAGE_SCAN_MODE1 0x01 -#define HCI_OPTIONAL_PAGE_SCAN_MODE2 0x02 -#define HCI_OPTIONAL_PAGE_SCAN_MODE3 0x03 -/* 0x04 - 0xFF - reserved for future use */ - -/* Page scan repetition modes */ -#define HCI_SCAN_REP_MODE0 0x00 -#define HCI_SCAN_REP_MODE1 0x01 -#define HCI_SCAN_REP_MODE2 0x02 -/* 0x03 - 0xFF - reserved for future use */ - -/* Page scan period modes */ -#define HCI_PAGE_SCAN_PERIOD_MODE0 0x00 -#define HCI_PAGE_SCAN_PERIOD_MODE1 0x01 -#define HCI_PAGE_SCAN_PERIOD_MODE2 0x02 -/* 0x03 - 0xFF - reserved for future use */ - -/* Scan enable */ -#define HCI_NO_SCAN_ENABLE 0x00 -#define HCI_INQUIRY_SCAN_ENABLE 0x01 -#define HCI_PAGE_SCAN_ENABLE 0x02 -/* 0x04 - 0xFF - reserved for future use */ - -/* Hold mode activities */ -#define HCI_HOLD_MODE_NO_CHANGE 0x00 -#define HCI_HOLD_MODE_SUSPEND_PAGE_SCAN 0x01 -#define HCI_HOLD_MODE_SUSPEND_INQUIRY_SCAN 0x02 -#define HCI_HOLD_MODE_SUSPEND_PERIOD_INQUIRY 0x04 -/* 0x08 - 0x80 - reserved for future use */ - -/* Connection roles */ -#define HCI_ROLE_MASTER 0x00 -#define HCI_ROLE_SLAVE 0x01 -/* 0x02 - 0xFF - reserved for future use */ - -/* Key flags */ -#define HCI_USE_SEMI_PERMANENT_LINK_KEYS 0x00 -#define HCI_USE_TEMPORARY_LINK_KEY 0x01 -/* 0x02 - 0xFF - reserved for future use */ - -/* Pin types */ -#define HCI_PIN_TYPE_VARIABLE 0x00 -#define HCI_PIN_TYPE_FIXED 0x01 - -/* Link key types */ -#define HCI_LINK_KEY_TYPE_COMBINATION_KEY 0x00 -#define HCI_LINK_KEY_TYPE_LOCAL_UNIT_KEY 0x01 -#define HCI_LINK_KEY_TYPE_REMOTE_UNIT_KEY 0x02 -/* 0x03 - 0xFF - reserved for future use */ - -/* Encryption modes */ -#define HCI_ENCRYPTION_MODE_NONE 0x00 -#define HCI_ENCRYPTION_MODE_P2P 0x01 -#define HCI_ENCRYPTION_MODE_ALL 0x02 -/* 0x03 - 0xFF - reserved for future use */ - -/* Quality of service types */ -#define HCI_SERVICE_TYPE_NO_TRAFFIC 0x00 -#define HCI_SERVICE_TYPE_BEST_EFFORT 0x01 -#define HCI_SERVICE_TYPE_GUARANTEED 0x02 -/* 0x03 - 0xFF - reserved for future use */ - -/* Link policy settings */ -#define HCI_LINK_POLICY_DISABLE_ALL_LM_MODES 0x0000 -#define HCI_LINK_POLICY_ENABLE_ROLE_SWITCH 0x0001 /* Master/Slave switch */ -#define HCI_LINK_POLICY_ENABLE_HOLD_MODE 0x0002 -#define HCI_LINK_POLICY_ENABLE_SNIFF_MODE 0x0004 -#define HCI_LINK_POLICY_ENABLE_PARK_MODE 0x0008 -/* 0x0010 - 0x8000 - reserved for future use */ - -/* Event masks */ -#define HCI_EVMSK_ALL 0x00000000ffffffff -#define HCI_EVMSK_NONE 0x0000000000000000 -#define HCI_EVMSK_INQUIRY_COMPL 0x0000000000000001 -#define HCI_EVMSK_INQUIRY_RESULT 0x0000000000000002 -#define HCI_EVMSK_CON_COMPL 0x0000000000000004 -#define HCI_EVMSK_CON_REQ 0x0000000000000008 -#define HCI_EVMSK_DISCON_COMPL 0x0000000000000010 -#define HCI_EVMSK_AUTH_COMPL 0x0000000000000020 -#define HCI_EVMSK_REMOTE_NAME_REQ_COMPL 0x0000000000000040 -#define HCI_EVMSK_ENCRYPTION_CHANGE 0x0000000000000080 -#define HCI_EVMSK_CHANGE_CON_LINK_KEY_COMPL 0x0000000000000100 -#define HCI_EVMSK_MASTER_LINK_KEY_COMPL 0x0000000000000200 -#define HCI_EVMSK_READ_REMOTE_FEATURES_COMPL 0x0000000000000400 -#define HCI_EVMSK_READ_REMOTE_VER_INFO_COMPL 0x0000000000000800 -#define HCI_EVMSK_QOS_SETUP_COMPL 0x0000000000001000 -#define HCI_EVMSK_COMMAND_COMPL 0x0000000000002000 -#define HCI_EVMSK_COMMAND_STATUS 0x0000000000004000 -#define HCI_EVMSK_HARDWARE_ERROR 0x0000000000008000 -#define HCI_EVMSK_FLUSH_OCCUR 0x0000000000010000 -#define HCI_EVMSK_ROLE_CHANGE 0x0000000000020000 -#define HCI_EVMSK_NUM_COMPL_PKTS 0x0000000000040000 -#define HCI_EVMSK_MODE_CHANGE 0x0000000000080000 -#define HCI_EVMSK_RETURN_LINK_KEYS 0x0000000000100000 -#define HCI_EVMSK_PIN_CODE_REQ 0x0000000000200000 -#define HCI_EVMSK_LINK_KEY_REQ 0x0000000000400000 -#define HCI_EVMSK_LINK_KEY_NOTIFICATION 0x0000000000800000 -#define HCI_EVMSK_LOOPBACK_COMMAND 0x0000000001000000 -#define HCI_EVMSK_DATA_BUFFER_OVERFLOW 0x0000000002000000 -#define HCI_EVMSK_MAX_SLOT_CHANGE 0x0000000004000000 -#define HCI_EVMSK_READ_CLOCK_OFFSET_COMLETE 0x0000000008000000 -#define HCI_EVMSK_CON_PKT_TYPE_CHANGED 0x0000000010000000 -#define HCI_EVMSK_QOS_VIOLATION 0x0000000020000000 -#define HCI_EVMSK_PAGE_SCAN_MODE_CHANGE 0x0000000040000000 -#define HCI_EVMSK_PAGE_SCAN_REP_MODE_CHANGE 0x0000000080000000 -/* 0x0000000100000000 - 0x8000000000000000 - reserved for future use */ - -/* Filter types */ -#define HCI_FILTER_TYPE_NONE 0x00 -#define HCI_FILTER_TYPE_INQUIRY_RESULT 0x01 -#define HCI_FILTER_TYPE_CON_SETUP 0x02 -/* 0x03 - 0xFF - reserved for future use */ - -/* Filter condition types for HCI_FILTER_TYPE_INQUIRY_RESULT */ -#define HCI_FILTER_COND_INQUIRY_NEW_UNIT 0x00 -#define HCI_FILTER_COND_INQUIRY_UNIT_CLASS 0x01 -#define HCI_FILTER_COND_INQUIRY_BDADDR 0x02 -/* 0x03 - 0xFF - reserved for future use */ - -/* Filter condition types for HCI_FILTER_TYPE_CON_SETUP */ -#define HCI_FILTER_COND_CON_ANY_UNIT 0x00 -#define HCI_FILTER_COND_CON_UNIT_CLASS 0x01 -#define HCI_FILTER_COND_CON_BDADDR 0x02 -/* 0x03 - 0xFF - reserved for future use */ - -/* Xmit level types */ -#define HCI_XMIT_LEVEL_CURRENT 0x00 -#define HCI_XMIT_LEVEL_MAXIMUM 0x01 -/* 0x02 - 0xFF - reserved for future use */ - -/* Host Controller to Host flow control */ -#define HCI_HC2H_FLOW_CONTROL_NONE 0x00 -#define HCI_HC2H_FLOW_CONTROL_ACL 0x01 -#define HCI_HC2H_FLOW_CONTROL_SCO 0x02 -#define HCI_HC2H_FLOW_CONTROL_BOTH 0x03 -/* 0x04 - 0xFF - reserved future use */ - -/* Loopback modes */ -#define HCI_LOOPBACK_NONE 0x00 -#define HCI_LOOPBACK_LOCAL 0x01 -#define HCI_LOOPBACK_REMOTE 0x02 -/* 0x03 - 0xFF - reserved future use */ - -/************************************************************************** - ************************************************************************** - ** Link level defines, headers and types - ************************************************************************** - **************************************************************************/ - -/* - * Macro(s) to combine OpCode and extract OGF (OpCode Group Field) - * and OCF (OpCode Command Field) from OpCode. - */ - -#define HCI_OPCODE(gf,cf) ((((gf) & 0x3f) << 10) | ((cf) & 0x3ff)) -#define HCI_OCF(op) ((op) & 0x3ff) -#define HCI_OGF(op) (((op) >> 10) & 0x3f) - -/* - * Macro(s) to extract/combine connection handle, BC (Broadcast) and - * PB (Packet boundary) flags. - */ - -#define HCI_CON_HANDLE(h) ((h) & 0x0fff) -#define HCI_PB_FLAG(h) (((h) & 0x3000) >> 12) -#define HCI_BC_FLAG(h) (((h) & 0xc000) >> 14) -#define HCI_MK_CON_HANDLE(h, pb, bc) \ - (((h) & 0x0fff) | (((pb) & 3) << 12) | (((bc) & 3) << 14)) - -/* PB flag values */ - /* 00 - reserved for future use */ -#define HCI_PACKET_FRAGMENT 0x1 -#define HCI_PACKET_START 0x2 - /* 11 - reserved for future use */ - -/* BC flag values */ -#define HCI_POINT2POINT 0x0 /* only Host controller to Host */ -#define HCI_BROADCAST_ACTIVE 0x1 /* both directions */ -#define HCI_BROADCAST_PICONET 0x2 /* both directions */ - /* 11 - reserved for future use */ - -/* HCI command packet header */ -typedef struct { - uint8_t type; /* MUST be 0x01 */ - uint16_t opcode; /* OpCode */ - uint8_t length; /* parameter(s) length in bytes */ -} __packed hci_cmd_hdr_t; - -#define HCI_CMD_PKT 0x01 -#define HCI_CMD_PKT_SIZE (sizeof(hci_cmd_hdr_t) + 0xff) - -/* ACL data packet header */ -typedef struct { - uint8_t type; /* MUST be 0x02 */ - uint16_t con_handle; /* connection handle + PB + BC flags */ - uint16_t length; /* payload length in bytes */ -} __packed hci_acldata_hdr_t; - -#define HCI_ACL_DATA_PKT 0x02 -#define HCI_ACL_PKT_SIZE (sizeof(hci_acldata_hdr_t) + 0xffff) - -/* SCO data packet header */ -typedef struct { - uint8_t type; /* MUST be 0x03 */ - uint16_t con_handle; /* connection handle + reserved bits */ - uint8_t length; /* payload length in bytes */ -} __packed hci_scodata_hdr_t; - -#define HCI_SCO_DATA_PKT 0x03 -#define HCI_SCO_PKT_SIZE (sizeof(hci_scodata_hdr_t) + 0xff) - -/* HCI event packet header */ -typedef struct { - uint8_t type; /* MUST be 0x04 */ - uint8_t event; /* event */ - uint8_t length; /* parameter(s) length in bytes */ -} __packed hci_event_hdr_t; - -#define HCI_EVENT_PKT 0x04 -#define HCI_EVENT_PKT_SIZE (sizeof(hci_event_hdr_t) + 0xff) - -/* HCI status return parameter */ -typedef struct { - uint8_t status; /* 0x00 - success */ -} __packed hci_status_rp; - -/************************************************************************** - ************************************************************************** - ** OGF 0x01 Link control commands and return parameters - ************************************************************************** - **************************************************************************/ - -#define HCI_OGF_LINK_CONTROL 0x01 - -#define HCI_OCF_INQUIRY 0x0001 -#define HCI_CMD_INQUIRY 0x0401 -typedef struct { - uint8_t lap[HCI_LAP_SIZE]; /* LAP */ - uint8_t inquiry_length; /* (N x 1.28) sec */ - uint8_t num_responses; /* Max. # of responses */ -} __packed hci_inquiry_cp; -/* No return parameter(s) */ - -#define HCI_OCF_INQUIRY_CANCEL 0x0002 -#define HCI_CMD_INQUIRY_CANCEL 0x0402 -/* No command parameter(s) */ -typedef hci_status_rp hci_inquiry_cancel_rp; - -#define HCI_OCF_PERIODIC_INQUIRY 0x0003 -#define HCI_CMD_PERIODIC_INQUIRY 0x0403 -typedef struct { - uint16_t max_period_length; /* Max. and min. amount of time */ - uint16_t min_period_length; /* between consecutive inquiries */ - uint8_t lap[HCI_LAP_SIZE]; /* LAP */ - uint8_t inquiry_length; /* (inquiry_length * 1.28) sec */ - uint8_t num_responses; /* Max. # of responses */ -} __packed hci_periodic_inquiry_cp; - -typedef hci_status_rp hci_periodic_inquiry_rp; - -#define HCI_OCF_EXIT_PERIODIC_INQUIRY 0x0004 -#define HCI_CMD_EXIT_PERIODIC_INQUIRY 0x0404 -/* No command parameter(s) */ -typedef hci_status_rp hci_exit_periodic_inquiry_rp; - -#define HCI_OCF_CREATE_CON 0x0005 -#define HCI_CMD_CREATE_CON 0x0405 -typedef struct { - bdaddr_t bdaddr; /* destination address */ - uint16_t pkt_type; /* packet type */ - uint8_t page_scan_rep_mode; /* page scan repetition mode */ - uint8_t page_scan_mode; /* reserved - set to 0x00 */ - uint16_t clock_offset; /* clock offset */ - uint8_t accept_role_switch; /* accept role switch? 0x00 == No */ -} __packed hci_create_con_cp; -/* No return parameter(s) */ - -#define HCI_OCF_DISCONNECT 0x0006 -#define HCI_CMD_DISCONNECT 0x0406 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t reason; /* reason to disconnect */ -} __packed hci_discon_cp; -/* No return parameter(s) */ - -/* Add SCO Connection is deprecated */ -#define HCI_OCF_ADD_SCO_CON 0x0007 -#define HCI_CMD_ADD_SCO_CON 0x0407 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t pkt_type; /* packet type */ -} __packed hci_add_sco_con_cp; -/* No return parameter(s) */ - -#define HCI_OCF_CREATE_CON_CANCEL 0x0008 -#define HCI_CMD_CREATE_CON_CANCEL 0x0408 -typedef struct { - bdaddr_t bdaddr; /* destination address */ -} __packed hci_create_con_cancel_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* destination address */ -} __packed hci_create_con_cancel_rp; - -#define HCI_OCF_ACCEPT_CON 0x0009 -#define HCI_CMD_ACCEPT_CON 0x0409 -typedef struct { - bdaddr_t bdaddr; /* address of unit to be connected */ - uint8_t role; /* connection role */ -} __packed hci_accept_con_cp; -/* No return parameter(s) */ - -#define HCI_OCF_REJECT_CON 0x000a -#define HCI_CMD_REJECT_CON 0x040A -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t reason; /* reason to reject */ -} __packed hci_reject_con_cp; -/* No return parameter(s) */ - -#define HCI_OCF_LINK_KEY_REP 0x000b -#define HCI_CMD_LINK_KEY_REP 0x040B -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t key[HCI_KEY_SIZE]; /* key */ -} __packed hci_link_key_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* unit address */ -} __packed hci_link_key_rep_rp; - -#define HCI_OCF_LINK_KEY_NEG_REP 0x000c -#define HCI_CMD_LINK_KEY_NEG_REP 0x040C -typedef struct { - bdaddr_t bdaddr; /* remote address */ -} __packed hci_link_key_neg_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* unit address */ -} __packed hci_link_key_neg_rep_rp; - -#define HCI_OCF_PIN_CODE_REP 0x000d -#define HCI_CMD_PIN_CODE_REP 0x040D -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t pin_size; /* pin code length (in bytes) */ - uint8_t pin[HCI_PIN_SIZE]; /* pin code */ -} __packed hci_pin_code_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* unit address */ -} __packed hci_pin_code_rep_rp; - -#define HCI_OCF_PIN_CODE_NEG_REP 0x000e -#define HCI_CMD_PIN_CODE_NEG_REP 0x040E -typedef struct { - bdaddr_t bdaddr; /* remote address */ -} __packed hci_pin_code_neg_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* unit address */ -} __packed hci_pin_code_neg_rep_rp; - -#define HCI_OCF_CHANGE_CON_PACKET_TYPE 0x000f -#define HCI_CMD_CHANGE_CON_PACKET_TYPE 0x040F -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t pkt_type; /* packet type */ -} __packed hci_change_con_pkt_type_cp; -/* No return parameter(s) */ - -#define HCI_OCF_AUTH_REQ 0x0011 -#define HCI_CMD_AUTH_REQ 0x0411 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_auth_req_cp; -/* No return parameter(s) */ - -#define HCI_OCF_SET_CON_ENCRYPTION 0x0013 -#define HCI_CMD_SET_CON_ENCRYPTION 0x0413 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t encryption_enable; /* 0x00 - disable, 0x01 - enable */ -} __packed hci_set_con_encryption_cp; -/* No return parameter(s) */ - -#define HCI_OCF_CHANGE_CON_LINK_KEY 0x0015 -#define HCI_CMD_CHANGE_CON_LINK_KEY 0x0415 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_change_con_link_key_cp; -/* No return parameter(s) */ - -#define HCI_OCF_MASTER_LINK_KEY 0x0017 -#define HCI_CMD_MASTER_LINK_KEY 0x0417 -typedef struct { - uint8_t key_flag; /* key flag */ -} __packed hci_master_link_key_cp; -/* No return parameter(s) */ - -#define HCI_OCF_REMOTE_NAME_REQ 0x0019 -#define HCI_CMD_REMOTE_NAME_REQ 0x0419 -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t page_scan_rep_mode; /* page scan repetition mode */ - uint8_t page_scan_mode; /* page scan mode */ - uint16_t clock_offset; /* clock offset */ -} __packed hci_remote_name_req_cp; -/* No return parameter(s) */ - -#define HCI_OCF_REMOTE_NAME_REQ_CANCEL 0x001a -#define HCI_CMD_REMOTE_NAME_REQ_CANCEL 0x041A -typedef struct { - bdaddr_t bdaddr; /* remote address */ -} __packed hci_remote_name_req_cancel_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ -} __packed hci_remote_name_req_cancel_rp; - -#define HCI_OCF_READ_REMOTE_FEATURES 0x001b -#define HCI_CMD_READ_REMOTE_FEATURES 0x041B -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_remote_features_cp; -/* No return parameter(s) */ - -#define HCI_OCF_READ_REMOTE_EXTENDED_FEATURES 0x001c -#define HCI_CMD_READ_REMOTE_EXTENDED_FEATURES 0x041C -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t page; /* page number */ -} __packed hci_read_remote_extended_features_cp; -/* No return parameter(s) */ - -#define HCI_OCF_READ_REMOTE_VER_INFO 0x001d -#define HCI_CMD_READ_REMOTE_VER_INFO 0x041D -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_remote_ver_info_cp; -/* No return parameter(s) */ - -#define HCI_OCF_READ_CLOCK_OFFSET 0x001f -#define HCI_CMD_READ_CLOCK_OFFSET 0x041F -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_clock_offset_cp; -/* No return parameter(s) */ - -#define HCI_OCF_READ_LMP_HANDLE 0x0020 -#define HCI_CMD_READ_LMP_HANDLE 0x0420 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_lmp_handle_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t lmp_handle; /* LMP handle */ - uint32_t reserved; /* reserved */ -} __packed hci_read_lmp_handle_rp; - -#define HCI_OCF_SETUP_SCO_CON 0x0028 -#define HCI_CMD_SETUP_SCO_CON 0x0428 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint32_t tx_bandwidth; /* transmit bandwidth */ - uint32_t rx_bandwidth; /* receive bandwidth */ - uint16_t latency; /* maximum latency */ - uint16_t voice; /* voice setting */ - uint8_t rt_effort; /* retransmission effort */ - uint16_t pkt_type; /* packet types */ -} __packed hci_setup_sco_con_cp; -/* No return parameter(s) */ - -#define HCI_OCF_ACCEPT_SCO_CON_REQ 0x0029 -#define HCI_CMD_ACCEPT_SCO_CON_REQ 0x0429 -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint32_t tx_bandwidth; /* transmit bandwidth */ - uint32_t rx_bandwidth; /* receive bandwidth */ - uint16_t latency; /* maximum latency */ - uint16_t content; /* voice setting */ - uint8_t rt_effort; /* retransmission effort */ - uint16_t pkt_type; /* packet types */ -} __packed hci_accept_sco_con_req_cp; -/* No return parameter(s) */ - -#define HCI_OCF_REJECT_SCO_CON_REQ 0x002a -#define HCI_CMD_REJECT_SCO_CON_REQ 0x042a -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t reason; /* reject error code */ -} __packed hci_reject_sco_con_req_cp; -/* No return parameter(s) */ - -#define HCI_OCF_IO_CAPABILITY_REP 0x002b -#define HCI_CMD_IO_CAPABILITY_REP 0x042a -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t io_cap; /* IO capability */ - uint8_t oob_data; /* OOB data present */ - uint8_t auth_req; /* auth requirements */ -} __packed hci_io_capability_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ -} __packed hci_io_capability_rep_rp; - -#define HCI_OCF_USER_CONFIRM_REP 0x002c -#define HCI_CMD_USER_CONFIRM_REP 0x042c -typedef struct { - bdaddr_t bdaddr; /* remote address */ -} __packed hci_user_confirm_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ -} __packed hci_user_confirm_rep_rp; - -#define HCI_OCF_USER_CONFIRM_NEG_REP 0x002d -#define HCI_CMD_USER_CONFIRM_NEG_REP 0x042d -typedef struct { - bdaddr_t bdaddr; /* remote address */ -} __packed hci_user_confirm_neg_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ -} __packed hci_user_confirm_neg_rep_rp; - -#define HCI_OCF_USER_PASSKEY_REP 0x002e -#define HCI_CMD_USER_PASSKEY_REP 0x042e -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint32_t value; /* 000000 - 999999 */ -} __packed hci_user_passkey_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ -} __packed hci_user_passkey_rep_rp; - -#define HCI_OCF_USER_PASSKEY_NEG_REP 0x002f -#define HCI_CMD_USER_PASSKEY_NEG_REP 0x042f -typedef struct { - bdaddr_t bdaddr; /* remote address */ -} __packed hci_user_passkey_neg_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ -} __packed hci_user_passkey_neg_rep_rp; - -#define HCI_OCF_OOB_DATA_REP 0x0030 -#define HCI_CMD_OOB_DATA_REP 0x0430 -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t c[16]; /* pairing hash */ - uint8_t r[16]; /* pairing randomizer */ -} __packed hci_user_oob_data_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ -} __packed hci_user_oob_data_rep_rp; - -#define HCI_OCF_OOB_DATA_NEG_REP 0x0033 -#define HCI_CMD_OOB_DATA_NEG_REP 0x0433 -typedef struct { - bdaddr_t bdaddr; /* remote address */ -} __packed hci_user_oob_data_neg_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ -} __packed hci_user_oob_data_neg_rep_rp; - -#define HCI_OCF_IO_CAPABILITY_NEG_REP 0x0034 -#define HCI_CMD_IO_CAPABILITY_NEG_REP 0x0434 -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t reason; /* error code */ -} __packed hci_io_capability_neg_rep_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ -} __packed hci_io_capability_neg_rep_rp; - -/************************************************************************** - ************************************************************************** - ** OGF 0x02 Link policy commands and return parameters - ************************************************************************** - **************************************************************************/ - -#define HCI_OGF_LINK_POLICY 0x02 - -#define HCI_OCF_HOLD_MODE 0x0001 -#define HCI_CMD_HOLD_MODE 0x0801 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t max_interval; /* (max_interval * 0.625) msec */ - uint16_t min_interval; /* (max_interval * 0.625) msec */ -} __packed hci_hold_mode_cp; -/* No return parameter(s) */ - -#define HCI_OCF_SNIFF_MODE 0x0003 -#define HCI_CMD_SNIFF_MODE 0x0803 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t max_interval; /* (max_interval * 0.625) msec */ - uint16_t min_interval; /* (max_interval * 0.625) msec */ - uint16_t attempt; /* (2 * attempt - 1) * 0.625 msec */ - uint16_t timeout; /* (2 * attempt - 1) * 0.625 msec */ -} __packed hci_sniff_mode_cp; -/* No return parameter(s) */ - -#define HCI_OCF_EXIT_SNIFF_MODE 0x0004 -#define HCI_CMD_EXIT_SNIFF_MODE 0x0804 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_exit_sniff_mode_cp; -/* No return parameter(s) */ - -#define HCI_OCF_PARK_MODE 0x0005 -#define HCI_CMD_PARK_MODE 0x0805 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t max_interval; /* (max_interval * 0.625) msec */ - uint16_t min_interval; /* (max_interval * 0.625) msec */ -} __packed hci_park_mode_cp; -/* No return parameter(s) */ - -#define HCI_OCF_EXIT_PARK_MODE 0x0006 -#define HCI_CMD_EXIT_PARK_MODE 0x0806 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_exit_park_mode_cp; -/* No return parameter(s) */ - -#define HCI_OCF_QOS_SETUP 0x0007 -#define HCI_CMD_QOS_SETUP 0x0807 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t flags; /* reserved for future use */ - uint8_t service_type; /* service type */ - uint32_t token_rate; /* bytes per second */ - uint32_t peak_bandwidth; /* bytes per second */ - uint32_t latency; /* microseconds */ - uint32_t delay_variation; /* microseconds */ -} __packed hci_qos_setup_cp; -/* No return parameter(s) */ - -#define HCI_OCF_ROLE_DISCOVERY 0x0009 -#define HCI_CMD_ROLE_DISCOVERY 0x0809 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_role_discovery_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t role; /* role for the connection handle */ -} __packed hci_role_discovery_rp; - -#define HCI_OCF_SWITCH_ROLE 0x000b -#define HCI_CMD_SWITCH_ROLE 0x080B -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t role; /* new local role */ -} __packed hci_switch_role_cp; -/* No return parameter(s) */ - -#define HCI_OCF_READ_LINK_POLICY_SETTINGS 0x000c -#define HCI_CMD_READ_LINK_POLICY_SETTINGS 0x080C -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_link_policy_settings_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t settings; /* link policy settings */ -} __packed hci_read_link_policy_settings_rp; - -#define HCI_OCF_WRITE_LINK_POLICY_SETTINGS 0x000d -#define HCI_CMD_WRITE_LINK_POLICY_SETTINGS 0x080D -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t settings; /* link policy settings */ -} __packed hci_write_link_policy_settings_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ -} __packed hci_write_link_policy_settings_rp; - -#define HCI_OCF_READ_DEFAULT_LINK_POLICY_SETTINGS 0x000e -#define HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS 0x080E -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t settings; /* link policy settings */ -} __packed hci_read_default_link_policy_settings_rp; - -#define HCI_OCF_WRITE_DEFAULT_LINK_POLICY_SETTINGS 0x000f -#define HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS 0x080F -typedef struct { - uint16_t settings; /* link policy settings */ -} __packed hci_write_default_link_policy_settings_cp; - -typedef hci_status_rp hci_write_default_link_policy_settings_rp; - -#define HCI_OCF_FLOW_SPECIFICATION 0x0010 -#define HCI_CMD_FLOW_SPECIFICATION 0x0810 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t flags; /* reserved */ - uint8_t flow_direction; - uint8_t service_type; - uint32_t token_rate; - uint32_t token_bucket; - uint32_t peak_bandwidth; - uint32_t latency; -} __packed hci_flow_specification_cp; -/* No return parameter(s) */ - -#define HCI_OCF_SNIFF_SUBRATING 0x0011 -#define HCI_CMD_SNIFF_SUBRATING 0x0810 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t max_latency; - uint16_t max_timeout; /* max remote timeout */ - uint16_t min_timeout; /* min local timeout */ -} __packed hci_sniff_subrating_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ -} __packed hci_sniff_subrating_rp; - -/************************************************************************** - ************************************************************************** - ** OGF 0x03 Host Controller and Baseband commands and return parameters - ************************************************************************** - **************************************************************************/ - -#define HCI_OGF_HC_BASEBAND 0x03 - -#define HCI_OCF_SET_EVENT_MASK 0x0001 -#define HCI_CMD_SET_EVENT_MASK 0x0C01 -typedef struct { - uint8_t event_mask[HCI_EVENT_MASK_SIZE]; /* event_mask */ -} __packed hci_set_event_mask_cp; - -typedef hci_status_rp hci_set_event_mask_rp; - -#define HCI_OCF_RESET 0x0003 -#define HCI_CMD_RESET 0x0C03 -/* No command parameter(s) */ -typedef hci_status_rp hci_reset_rp; - -#define HCI_OCF_SET_EVENT_FILTER 0x0005 -#define HCI_CMD_SET_EVENT_FILTER 0x0C05 -typedef struct { - uint8_t filter_type; /* filter type */ - uint8_t filter_condition_type; /* filter condition type */ -/* variable size condition - uint8_t condition[]; -- conditions */ -} __packed hci_set_event_filter_cp; - -typedef hci_status_rp hci_set_event_filter_rp; - -#define HCI_OCF_FLUSH 0x0008 -#define HCI_CMD_FLUSH 0x0C08 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_flush_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ -} __packed hci_flush_rp; - -#define HCI_OCF_READ_PIN_TYPE 0x0009 -#define HCI_CMD_READ_PIN_TYPE 0x0C09 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t pin_type; /* PIN type */ -} __packed hci_read_pin_type_rp; - -#define HCI_OCF_WRITE_PIN_TYPE 0x000a -#define HCI_CMD_WRITE_PIN_TYPE 0x0C0A -typedef struct { - uint8_t pin_type; /* PIN type */ -} __packed hci_write_pin_type_cp; - -typedef hci_status_rp hci_write_pin_type_rp; - -#define HCI_OCF_CREATE_NEW_UNIT_KEY 0x000b -#define HCI_CMD_CREATE_NEW_UNIT_KEY 0x0C0B -/* No command parameter(s) */ -typedef hci_status_rp hci_create_new_unit_key_rp; - -#define HCI_OCF_READ_STORED_LINK_KEY 0x000d -#define HCI_CMD_READ_STORED_LINK_KEY 0x0C0D -typedef struct { - bdaddr_t bdaddr; /* address */ - uint8_t read_all; /* read all keys? 0x01 - yes */ -} __packed hci_read_stored_link_key_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t max_num_keys; /* Max. number of keys */ - uint16_t num_keys_read; /* Number of stored keys */ -} __packed hci_read_stored_link_key_rp; - -#define HCI_OCF_WRITE_STORED_LINK_KEY 0x0011 -#define HCI_CMD_WRITE_STORED_LINK_KEY 0x0C11 -typedef struct { - uint8_t num_keys_write; /* # of keys to write */ -/* these are repeated "num_keys_write" times - bdaddr_t bdaddr; --- remote address(es) - uint8_t key[HCI_KEY_SIZE]; --- key(s) */ -} __packed hci_write_stored_link_key_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t num_keys_written; /* # of keys successfully written */ -} __packed hci_write_stored_link_key_rp; - -#define HCI_OCF_DELETE_STORED_LINK_KEY 0x0012 -#define HCI_CMD_DELETE_STORED_LINK_KEY 0x0C12 -typedef struct { - bdaddr_t bdaddr; /* address */ - uint8_t delete_all; /* delete all keys? 0x01 - yes */ -} __packed hci_delete_stored_link_key_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t num_keys_deleted; /* Number of keys deleted */ -} __packed hci_delete_stored_link_key_rp; - -#define HCI_OCF_WRITE_LOCAL_NAME 0x0013 -#define HCI_CMD_WRITE_LOCAL_NAME 0x0C13 -typedef struct { - char name[HCI_UNIT_NAME_SIZE]; /* new unit name */ -} __packed hci_write_local_name_cp; - -typedef hci_status_rp hci_write_local_name_rp; - -#define HCI_OCF_READ_LOCAL_NAME 0x0014 -#define HCI_CMD_READ_LOCAL_NAME 0x0C14 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - char name[HCI_UNIT_NAME_SIZE]; /* unit name */ -} __packed hci_read_local_name_rp; - -#define HCI_OCF_READ_CON_ACCEPT_TIMEOUT 0x0015 -#define HCI_CMD_READ_CON_ACCEPT_TIMEOUT 0x0C15 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t timeout; /* (timeout * 0.625) msec */ -} __packed hci_read_con_accept_timeout_rp; - -#define HCI_OCF_WRITE_CON_ACCEPT_TIMEOUT 0x0016 -#define HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT 0x0C16 -typedef struct { - uint16_t timeout; /* (timeout * 0.625) msec */ -} __packed hci_write_con_accept_timeout_cp; - -typedef hci_status_rp hci_write_con_accept_timeout_rp; - -#define HCI_OCF_READ_PAGE_TIMEOUT 0x0017 -#define HCI_CMD_READ_PAGE_TIMEOUT 0x0C17 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t timeout; /* (timeout * 0.625) msec */ -} __packed hci_read_page_timeout_rp; - -#define HCI_OCF_WRITE_PAGE_TIMEOUT 0x0018 -#define HCI_CMD_WRITE_PAGE_TIMEOUT 0x0C18 -typedef struct { - uint16_t timeout; /* (timeout * 0.625) msec */ -} __packed hci_write_page_timeout_cp; - -typedef hci_status_rp hci_write_page_timeout_rp; - -#define HCI_OCF_READ_SCAN_ENABLE 0x0019 -#define HCI_CMD_READ_SCAN_ENABLE 0x0C19 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t scan_enable; /* Scan enable */ -} __packed hci_read_scan_enable_rp; - -#define HCI_OCF_WRITE_SCAN_ENABLE 0x001a -#define HCI_CMD_WRITE_SCAN_ENABLE 0x0C1A -typedef struct { - uint8_t scan_enable; /* Scan enable */ -} __packed hci_write_scan_enable_cp; - -typedef hci_status_rp hci_write_scan_enable_rp; - -#define HCI_OCF_READ_PAGE_SCAN_ACTIVITY 0x001b -#define HCI_CMD_READ_PAGE_SCAN_ACTIVITY 0x0C1B -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t page_scan_interval; /* interval * 0.625 msec */ - uint16_t page_scan_window; /* window * 0.625 msec */ -} __packed hci_read_page_scan_activity_rp; - -#define HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY 0x001c -#define HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY 0x0C1C -typedef struct { - uint16_t page_scan_interval; /* interval * 0.625 msec */ - uint16_t page_scan_window; /* window * 0.625 msec */ -} __packed hci_write_page_scan_activity_cp; - -typedef hci_status_rp hci_write_page_scan_activity_rp; - -#define HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY 0x001d -#define HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY 0x0C1D -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t inquiry_scan_interval; /* interval * 0.625 msec */ - uint16_t inquiry_scan_window; /* window * 0.625 msec */ -} __packed hci_read_inquiry_scan_activity_rp; - -#define HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY 0x001e -#define HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY 0x0C1E -typedef struct { - uint16_t inquiry_scan_interval; /* interval * 0.625 msec */ - uint16_t inquiry_scan_window; /* window * 0.625 msec */ -} __packed hci_write_inquiry_scan_activity_cp; - -typedef hci_status_rp hci_write_inquiry_scan_activity_rp; - -#define HCI_OCF_READ_AUTH_ENABLE 0x001f -#define HCI_CMD_READ_AUTH_ENABLE 0x0C1F -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t auth_enable; /* 0x01 - enabled */ -} __packed hci_read_auth_enable_rp; - -#define HCI_OCF_WRITE_AUTH_ENABLE 0x0020 -#define HCI_CMD_WRITE_AUTH_ENABLE 0x0C20 -typedef struct { - uint8_t auth_enable; /* 0x01 - enabled */ -} __packed hci_write_auth_enable_cp; - -typedef hci_status_rp hci_write_auth_enable_rp; - -/* Read Encryption Mode is deprecated */ -#define HCI_OCF_READ_ENCRYPTION_MODE 0x0021 -#define HCI_CMD_READ_ENCRYPTION_MODE 0x0C21 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t encryption_mode; /* encryption mode */ -} __packed hci_read_encryption_mode_rp; - -/* Write Encryption Mode is deprecated */ -#define HCI_OCF_WRITE_ENCRYPTION_MODE 0x0022 -#define HCI_CMD_WRITE_ENCRYPTION_MODE 0x0C22 -typedef struct { - uint8_t encryption_mode; /* encryption mode */ -} __packed hci_write_encryption_mode_cp; - -typedef hci_status_rp hci_write_encryption_mode_rp; - -#define HCI_OCF_READ_UNIT_CLASS 0x0023 -#define HCI_CMD_READ_UNIT_CLASS 0x0C23 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ -} __packed hci_read_unit_class_rp; - -#define HCI_OCF_WRITE_UNIT_CLASS 0x0024 -#define HCI_CMD_WRITE_UNIT_CLASS 0x0C24 -typedef struct { - uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ -} __packed hci_write_unit_class_cp; - -typedef hci_status_rp hci_write_unit_class_rp; - -#define HCI_OCF_READ_VOICE_SETTING 0x0025 -#define HCI_CMD_READ_VOICE_SETTING 0x0C25 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t settings; /* voice settings */ -} __packed hci_read_voice_setting_rp; - -#define HCI_OCF_WRITE_VOICE_SETTING 0x0026 -#define HCI_CMD_WRITE_VOICE_SETTING 0x0C26 -typedef struct { - uint16_t settings; /* voice settings */ -} __packed hci_write_voice_setting_cp; - -typedef hci_status_rp hci_write_voice_setting_rp; - -#define HCI_OCF_READ_AUTO_FLUSH_TIMEOUT 0x0027 -#define HCI_CMD_READ_AUTO_FLUSH_TIMEOUT 0x0C27 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_auto_flush_timeout_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t timeout; /* 0x00 - no flush, timeout * 0.625 msec */ -} __packed hci_read_auto_flush_timeout_rp; - -#define HCI_OCF_WRITE_AUTO_FLUSH_TIMEOUT 0x0028 -#define HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT 0x0C28 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t timeout; /* 0x00 - no flush, timeout * 0.625 msec */ -} __packed hci_write_auto_flush_timeout_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ -} __packed hci_write_auto_flush_timeout_rp; - -#define HCI_OCF_READ_NUM_BROADCAST_RETRANS 0x0029 -#define HCI_CMD_READ_NUM_BROADCAST_RETRANS 0x0C29 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t counter; /* number of broadcast retransmissions */ -} __packed hci_read_num_broadcast_retrans_rp; - -#define HCI_OCF_WRITE_NUM_BROADCAST_RETRANS 0x002a -#define HCI_CMD_WRITE_NUM_BROADCAST_RETRANS 0x0C2A -typedef struct { - uint8_t counter; /* number of broadcast retransmissions */ -} __packed hci_write_num_broadcast_retrans_cp; - -typedef hci_status_rp hci_write_num_broadcast_retrans_rp; - -#define HCI_OCF_READ_HOLD_MODE_ACTIVITY 0x002b -#define HCI_CMD_READ_HOLD_MODE_ACTIVITY 0x0C2B -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t hold_mode_activity; /* Hold mode activities */ -} __packed hci_read_hold_mode_activity_rp; - -#define HCI_OCF_WRITE_HOLD_MODE_ACTIVITY 0x002c -#define HCI_CMD_WRITE_HOLD_MODE_ACTIVITY 0x0C2C -typedef struct { - uint8_t hold_mode_activity; /* Hold mode activities */ -} __packed hci_write_hold_mode_activity_cp; - -typedef hci_status_rp hci_write_hold_mode_activity_rp; - -#define HCI_OCF_READ_XMIT_LEVEL 0x002d -#define HCI_CMD_READ_XMIT_LEVEL 0x0C2D -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t type; /* Xmit level type */ -} __packed hci_read_xmit_level_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - char level; /* -30 <= level <= 30 dBm */ -} __packed hci_read_xmit_level_rp; - -#define HCI_OCF_READ_SCO_FLOW_CONTROL 0x002e -#define HCI_CMD_READ_SCO_FLOW_CONTROL 0x0C2E -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t flow_control; /* 0x00 - disabled */ -} __packed hci_read_sco_flow_control_rp; - -#define HCI_OCF_WRITE_SCO_FLOW_CONTROL 0x002f -#define HCI_CMD_WRITE_SCO_FLOW_CONTROL 0x0C2F -typedef struct { - uint8_t flow_control; /* 0x00 - disabled */ -} __packed hci_write_sco_flow_control_cp; - -typedef hci_status_rp hci_write_sco_flow_control_rp; - -#define HCI_OCF_HC2H_FLOW_CONTROL 0x0031 -#define HCI_CMD_HC2H_FLOW_CONTROL 0x0C31 -typedef struct { - uint8_t hc2h_flow; /* Host Controller to Host flow control */ -} __packed hci_hc2h_flow_control_cp; - -typedef hci_status_rp hci_h2hc_flow_control_rp; - -#define HCI_OCF_HOST_BUFFER_SIZE 0x0033 -#define HCI_CMD_HOST_BUFFER_SIZE 0x0C33 -typedef struct { - uint16_t max_acl_size; /* Max. size of ACL packet (bytes) */ - uint8_t max_sco_size; /* Max. size of SCO packet (bytes) */ - uint16_t num_acl_pkts; /* Max. number of ACL packets */ - uint16_t num_sco_pkts; /* Max. number of SCO packets */ -} __packed hci_host_buffer_size_cp; - -typedef hci_status_rp hci_host_buffer_size_rp; - -#define HCI_OCF_HOST_NUM_COMPL_PKTS 0x0035 -#define HCI_CMD_HOST_NUM_COMPL_PKTS 0x0C35 -typedef struct { - uint8_t nu_con_handles; /* # of connection handles */ -/* these are repeated "num_con_handles" times - uint16_t con_handle; --- connection handle(s) - uint16_t compl_pkts; --- # of completed packets */ -} __packed hci_host_num_compl_pkts_cp; -/* No return parameter(s) */ - -#define HCI_OCF_READ_LINK_SUPERVISION_TIMEOUT 0x0036 -#define HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT 0x0C36 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_link_supervision_timeout_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t timeout; /* Link supervision timeout * 0.625 msec */ -} __packed hci_read_link_supervision_timeout_rp; - -#define HCI_OCF_WRITE_LINK_SUPERVISION_TIMEOUT 0x0037 -#define HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT 0x0C37 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t timeout; /* Link supervision timeout * 0.625 msec */ -} __packed hci_write_link_supervision_timeout_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ -} __packed hci_write_link_supervision_timeout_rp; - -#define HCI_OCF_READ_NUM_SUPPORTED_IAC 0x0038 -#define HCI_CMD_READ_NUM_SUPPORTED_IAC 0x0C38 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t num_iac; /* # of supported IAC during scan */ -} __packed hci_read_num_supported_iac_rp; - -#define HCI_OCF_READ_IAC_LAP 0x0039 -#define HCI_CMD_READ_IAC_LAP 0x0C39 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t num_iac; /* # of IAC */ -/* these are repeated "num_iac" times - uint8_t laps[HCI_LAP_SIZE]; --- LAPs */ -} __packed hci_read_iac_lap_rp; - -#define HCI_OCF_WRITE_IAC_LAP 0x003a -#define HCI_CMD_WRITE_IAC_LAP 0x0C3A -typedef struct { - uint8_t num_iac; /* # of IAC */ -/* these are repeated "num_iac" times - uint8_t laps[HCI_LAP_SIZE]; --- LAPs */ -} __packed hci_write_iac_lap_cp; - -typedef hci_status_rp hci_write_iac_lap_rp; - -/* Read Page Scan Period Mode is deprecated */ -#define HCI_OCF_READ_PAGE_SCAN_PERIOD 0x003b -#define HCI_CMD_READ_PAGE_SCAN_PERIOD 0x0C3B -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t page_scan_period_mode; /* Page scan period mode */ -} __packed hci_read_page_scan_period_rp; - -/* Write Page Scan Period Mode is deprecated */ -#define HCI_OCF_WRITE_PAGE_SCAN_PERIOD 0x003c -#define HCI_CMD_WRITE_PAGE_SCAN_PERIOD 0x0C3C -typedef struct { - uint8_t page_scan_period_mode; /* Page scan period mode */ -} __packed hci_write_page_scan_period_cp; - -typedef hci_status_rp hci_write_page_scan_period_rp; - -/* Read Page Scan Mode is deprecated */ -#define HCI_OCF_READ_PAGE_SCAN 0x003d -#define HCI_CMD_READ_PAGE_SCAN 0x0C3D -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t page_scan_mode; /* Page scan mode */ -} __packed hci_read_page_scan_rp; - -/* Write Page Scan Mode is deprecated */ -#define HCI_OCF_WRITE_PAGE_SCAN 0x003e -#define HCI_CMD_WRITE_PAGE_SCAN 0x0C3E -typedef struct { - uint8_t page_scan_mode; /* Page scan mode */ -} __packed hci_write_page_scan_cp; - -typedef hci_status_rp hci_write_page_scan_rp; - -#define HCI_OCF_SET_AFH_CLASSIFICATION 0x003f -#define HCI_CMD_SET_AFH_CLASSIFICATION 0x0C3F -typedef struct { - uint8_t classification[10]; -} __packed hci_set_afh_classification_cp; - -typedef hci_status_rp hci_set_afh_classification_rp; - -#define HCI_OCF_READ_INQUIRY_SCAN_TYPE 0x0042 -#define HCI_CMD_READ_INQUIRY_SCAN_TYPE 0x0C42 -/* No command parameter(s) */ - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t type; /* inquiry scan type */ -} __packed hci_read_inquiry_scan_type_rp; - -#define HCI_OCF_WRITE_INQUIRY_SCAN_TYPE 0x0043 -#define HCI_CMD_WRITE_INQUIRY_SCAN_TYPE 0x0C43 -typedef struct { - uint8_t type; /* inquiry scan type */ -} __packed hci_write_inquiry_scan_type_cp; - -typedef hci_status_rp hci_write_inquiry_scan_type_rp; - -#define HCI_OCF_READ_INQUIRY_MODE 0x0044 -#define HCI_CMD_READ_INQUIRY_MODE 0x0C44 -/* No command parameter(s) */ - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t mode; /* inquiry mode */ -} __packed hci_read_inquiry_mode_rp; - -#define HCI_OCF_WRITE_INQUIRY_MODE 0x0045 -#define HCI_CMD_WRITE_INQUIRY_MODE 0x0C45 -typedef struct { - uint8_t mode; /* inquiry mode */ -} __packed hci_write_inquiry_mode_cp; - -typedef hci_status_rp hci_write_inquiry_mode_rp; - -#define HCI_OCF_READ_PAGE_SCAN_TYPE 0x0046 -#define HCI_CMD_READ_PAGE_SCAN_TYPE 0x0C46 -/* No command parameter(s) */ - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t type; /* page scan type */ -} __packed hci_read_page_scan_type_rp; - -#define HCI_OCF_WRITE_PAGE_SCAN_TYPE 0x0047 -#define HCI_CMD_WRITE_PAGE_SCAN_TYPE 0x0C47 -typedef struct { - uint8_t type; /* page scan type */ -} __packed hci_write_page_scan_type_cp; - -typedef hci_status_rp hci_write_page_scan_type_rp; - -#define HCI_OCF_READ_AFH_ASSESSMENT 0x0048 -#define HCI_CMD_READ_AFH_ASSESSMENT 0x0C48 -/* No command parameter(s) */ - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t mode; /* assessment mode */ -} __packed hci_read_afh_assessment_rp; - -#define HCI_OCF_WRITE_AFH_ASSESSMENT 0x0049 -#define HCI_CMD_WRITE_AFH_ASSESSMENT 0x0C49 -typedef struct { - uint8_t mode; /* assessment mode */ -} __packed hci_write_afh_assessment_cp; - -typedef hci_status_rp hci_write_afh_assessment_rp; - -#define HCI_OCF_READ_EXTENDED_INQUIRY_RSP 0x0051 -#define HCI_CMD_READ_EXTENDED_INQUIRY_RSP 0x0C51 -/* No command parameter(s) */ - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t fec_required; - uint8_t response[240]; -} __packed hci_read_extended_inquiry_rsp_rp; - -#define HCI_OCF_WRITE_EXTENDED_INQUIRY_RSP 0x0052 -#define HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP 0x0C52 -typedef struct { - uint8_t fec_required; - uint8_t response[240]; -} __packed hci_write_extended_inquiry_rsp_cp; - -typedef hci_status_rp hci_write_extended_inquiry_rsp_rp; - -#define HCI_OCF_REFRESH_ENCRYPTION_KEY 0x0053 -#define HCI_CMD_REFRESH_ENCRYPTION_KEY 0x0C53 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_refresh_encryption_key_cp; - -typedef hci_status_rp hci_refresh_encryption_key_rp; - -#define HCI_OCF_READ_SIMPLE_PAIRING_MODE 0x0055 -#define HCI_CMD_READ_SIMPLE_PAIRING_MODE 0x0C55 -/* No command parameter(s) */ - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t mode; /* simple pairing mode */ -} __packed hci_read_simple_pairing_mode_rp; - -#define HCI_OCF_WRITE_SIMPLE_PAIRING_MODE 0x0056 -#define HCI_CMD_WRITE_SIMPLE_PAIRING_MODE 0x0C56 -typedef struct { - uint8_t mode; /* simple pairing mode */ -} __packed hci_write_simple_pairing_mode_cp; - -typedef hci_status_rp hci_write_simple_pairing_mode_rp; - -#define HCI_OCF_READ_LOCAL_OOB_DATA 0x0057 -#define HCI_CMD_READ_LOCAL_OOB_DATA 0x0C57 -/* No command parameter(s) */ - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t c[16]; /* pairing hash */ - uint8_t r[16]; /* pairing randomizer */ -} __packed hci_read_local_oob_data_rp; - -#define HCI_OCF_READ_INQUIRY_RSP_XMIT_POWER 0x0058 -#define HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER 0x0C58 -/* No command parameter(s) */ - -typedef struct { - uint8_t status; /* 0x00 - success */ - int8_t power; /* TX power */ -} __packed hci_read_inquiry_rsp_xmit_power_rp; - -#define HCI_OCF_WRITE_INQUIRY_RSP_XMIT_POWER 0x0059 -#define HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER 0x0C59 -typedef struct { - int8_t power; /* TX power */ -} __packed hci_write_inquiry_rsp_xmit_power_cp; - -typedef hci_status_rp hci_write_inquiry_rsp_xmit_power_rp; - -#define HCI_OCF_READ_DEFAULT_ERRDATA_REPORTING 0x005A -#define HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING 0x0C5A -/* No command parameter(s) */ - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t reporting; /* erroneous data reporting */ -} __packed hci_read_default_errdata_reporting_rp; - -#define HCI_OCF_WRITE_DEFAULT_ERRDATA_REPORTING 0x005B -#define HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING 0x0C5B -typedef struct { - uint8_t reporting; /* erroneous data reporting */ -} __packed hci_write_default_errdata_reporting_cp; - -typedef hci_status_rp hci_write_default_errdata_reporting_rp; - -#define HCI_OCF_ENHANCED_FLUSH 0x005F -#define HCI_CMD_ENHANCED_FLUSH 0x0C5F -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t packet_type; -} __packed hci_enhanced_flush_cp; - -/* No response parameter(s) */ - -#define HCI_OCF_SEND_KEYPRESS_NOTIFICATION 0x0060 -#define HCI_CMD_SEND_KEYPRESS_NOTIFICATION 0x0C60 -typedef struct { - bdaddr_t bdaddr; /* remote address */ - uint8_t type; /* notification type */ -} __packed hci_send_keypress_notification_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote address */ -} __packed hci_send_keypress_notification_rp; - -/************************************************************************** - ************************************************************************** - ** OGF 0x04 Informational commands and return parameters - ************************************************************************** - **************************************************************************/ - -#define HCI_OGF_INFO 0x04 - -#define HCI_OCF_READ_LOCAL_VER 0x0001 -#define HCI_CMD_READ_LOCAL_VER 0x1001 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t hci_version; /* HCI version */ - uint16_t hci_revision; /* HCI revision */ - uint8_t lmp_version; /* LMP version */ - uint16_t manufacturer; /* Hardware manufacturer name */ - uint16_t lmp_subversion; /* LMP sub-version */ -} __packed hci_read_local_ver_rp; - -#define HCI_OCF_READ_LOCAL_COMMANDS 0x0002 -#define HCI_CMD_READ_LOCAL_COMMANDS 0x1002 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t commands[HCI_COMMANDS_SIZE]; /* opcode bitmask */ -} __packed hci_read_local_commands_rp; - -#define HCI_OCF_READ_LOCAL_FEATURES 0x0003 -#define HCI_CMD_READ_LOCAL_FEATURES 0x1003 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ -} __packed hci_read_local_features_rp; - -#define HCI_OCF_READ_LOCAL_EXTENDED_FEATURES 0x0004 -#define HCI_CMD_READ_LOCAL_EXTENDED_FEATURES 0x1004 -typedef struct { - uint8_t page; /* page number */ -} __packed hci_read_local_extended_features_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t page; /* page number */ - uint8_t max_page; /* maximum page number */ - uint8_t features[HCI_FEATURES_SIZE]; /* LMP features */ -} __packed hci_read_local_extended_features_rp; - -#define HCI_OCF_READ_BUFFER_SIZE 0x0005 -#define HCI_CMD_READ_BUFFER_SIZE 0x1005 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t max_acl_size; /* Max. size of ACL packet (bytes) */ - uint8_t max_sco_size; /* Max. size of SCO packet (bytes) */ - uint16_t num_acl_pkts; /* Max. number of ACL packets */ - uint16_t num_sco_pkts; /* Max. number of SCO packets */ -} __packed hci_read_buffer_size_rp; - -/* Read Country Code is deprecated */ -#define HCI_OCF_READ_COUNTRY_CODE 0x0007 -#define HCI_CMD_READ_COUNTRY_CODE 0x1007 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t country_code; /* 0x00 - NAM, EUR, JP; 0x01 - France */ -} __packed hci_read_country_code_rp; - -#define HCI_OCF_READ_BDADDR 0x0009 -#define HCI_CMD_READ_BDADDR 0x1009 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* unit address */ -} __packed hci_read_bdaddr_rp; - -/************************************************************************** - ************************************************************************** - ** OGF 0x05 Status commands and return parameters - ************************************************************************** - **************************************************************************/ - -#define HCI_OGF_STATUS 0x05 - -#define HCI_OCF_READ_FAILED_CONTACT_CNTR 0x0001 -#define HCI_CMD_READ_FAILED_CONTACT_CNTR 0x1401 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_failed_contact_cntr_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t counter; /* number of consecutive failed contacts */ -} __packed hci_read_failed_contact_cntr_rp; - -#define HCI_OCF_RESET_FAILED_CONTACT_CNTR 0x0002 -#define HCI_CMD_RESET_FAILED_CONTACT_CNTR 0x1402 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_reset_failed_contact_cntr_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ -} __packed hci_reset_failed_contact_cntr_rp; - -#define HCI_OCF_READ_LINK_QUALITY 0x0003 -#define HCI_CMD_READ_LINK_QUALITY 0x1403 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_link_quality_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t quality; /* higher value means better quality */ -} __packed hci_read_link_quality_rp; - -#define HCI_OCF_READ_RSSI 0x0005 -#define HCI_CMD_READ_RSSI 0x1405 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_rssi_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - char rssi; /* -127 <= rssi <= 127 dB */ -} __packed hci_read_rssi_rp; - -#define HCI_OCF_READ_AFH_CHANNEL_MAP 0x0006 -#define HCI_CMD_READ_AFH_CHANNEL_MAP 0x1406 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_read_afh_channel_map_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t mode; /* AFH mode */ - uint8_t map[10]; /* AFH Channel Map */ -} __packed hci_read_afh_channel_map_rp; - -#define HCI_OCF_READ_CLOCK 0x0007 -#define HCI_CMD_READ_CLOCK 0x1407 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t clock; /* which clock */ -} __packed hci_read_clock_cp; - -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint32_t clock; /* clock value */ - uint16_t accuracy; /* clock accuracy */ -} __packed hci_read_clock_rp; - - -/************************************************************************** - ************************************************************************** - ** OGF 0x06 Testing commands and return parameters - ************************************************************************** - **************************************************************************/ - -#define HCI_OGF_TESTING 0x06 - -#define HCI_OCF_READ_LOOPBACK_MODE 0x0001 -#define HCI_CMD_READ_LOOPBACK_MODE 0x1801 -/* No command parameter(s) */ -typedef struct { - uint8_t status; /* 0x00 - success */ - uint8_t lbmode; /* loopback mode */ -} __packed hci_read_loopback_mode_rp; - -#define HCI_OCF_WRITE_LOOPBACK_MODE 0x0002 -#define HCI_CMD_WRITE_LOOPBACK_MODE 0x1802 -typedef struct { - uint8_t lbmode; /* loopback mode */ -} __packed hci_write_loopback_mode_cp; - -typedef hci_status_rp hci_write_loopback_mode_rp; - -#define HCI_OCF_ENABLE_UNIT_UNDER_TEST 0x0003 -#define HCI_CMD_ENABLE_UNIT_UNDER_TEST 0x1803 -/* No command parameter(s) */ -typedef hci_status_rp hci_enable_unit_under_test_rp; - -#define HCI_OCF_WRITE_SIMPLE_PAIRING_DEBUG_MODE 0x0004 -#define HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE 0x1804 -typedef struct { - uint8_t mode; /* simple pairing debug mode */ -} __packed hci_write_simple_pairing_debug_mode_cp; - -typedef hci_status_rp hci_write_simple_pairing_debug_mode_rp; - -/************************************************************************** - ************************************************************************** - ** OGF 0x3e Bluetooth Logo Testing - ** OGF 0x3f Vendor Specific - ************************************************************************** - **************************************************************************/ - -#define HCI_OGF_BT_LOGO 0x3e -#define HCI_OGF_VENDOR 0x3f - -/* Ericsson specific FC */ -#define HCI_CMD_ERICSSON_WRITE_PCM_SETTINGS 0xFC07 -#define HCI_CMD_ERICSSON_SET_UART_BAUD_RATE 0xFC09 -#define HCI_CMD_ERICSSON_SET_SCO_DATA_PATH 0xFC1D - -/* Cambridge Silicon Radio specific FC */ -#define HCI_CMD_CSR_EXTN 0xFC00 - - -/************************************************************************** - ************************************************************************** - ** Events and event parameters - ************************************************************************** - **************************************************************************/ - -#define HCI_EVENT_INQUIRY_COMPL 0x01 -typedef struct { - uint8_t status; /* 0x00 - success */ -} __packed hci_inquiry_compl_ep; - -#define HCI_EVENT_INQUIRY_RESULT 0x02 -typedef struct { - uint8_t num_responses; /* number of responses */ -/* hci_inquiry_response[num_responses] -- see below */ -} __packed hci_inquiry_result_ep; - -typedef struct { - bdaddr_t bdaddr; /* unit address */ - uint8_t page_scan_rep_mode; /* page scan rep. mode */ - uint8_t page_scan_period_mode; /* page scan period mode */ - uint8_t page_scan_mode; /* page scan mode */ - uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ - uint16_t clock_offset; /* clock offset */ -} __packed hci_inquiry_response; - -#define HCI_EVENT_CON_COMPL 0x03 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - bdaddr_t bdaddr; /* remote unit address */ - uint8_t link_type; /* Link type */ - uint8_t encryption_mode; /* Encryption mode */ -} __packed hci_con_compl_ep; - -#define HCI_EVENT_CON_REQ 0x04 -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ - uint8_t uclass[HCI_CLASS_SIZE]; /* remote unit class */ - uint8_t link_type; /* link type */ -} __packed hci_con_req_ep; - -#define HCI_EVENT_DISCON_COMPL 0x05 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t reason; /* reason to disconnect */ -} __packed hci_discon_compl_ep; - -#define HCI_EVENT_AUTH_COMPL 0x06 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ -} __packed hci_auth_compl_ep; - -#define HCI_EVENT_REMOTE_NAME_REQ_COMPL 0x07 -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote unit address */ - char name[HCI_UNIT_NAME_SIZE]; /* remote unit name */ -} __packed hci_remote_name_req_compl_ep; - -#define HCI_EVENT_ENCRYPTION_CHANGE 0x08 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint8_t encryption_enable; /* 0x00 - disable */ -} __packed hci_encryption_change_ep; - -#define HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL 0x09 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ -} __packed hci_change_con_link_key_compl_ep; - -#define HCI_EVENT_MASTER_LINK_KEY_COMPL 0x0a -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint8_t key_flag; /* Key flag */ -} __packed hci_master_link_key_compl_ep; - -#define HCI_EVENT_READ_REMOTE_FEATURES_COMPL 0x0b -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ -} __packed hci_read_remote_features_compl_ep; - -#define HCI_EVENT_READ_REMOTE_VER_INFO_COMPL 0x0c -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint8_t lmp_version; /* LMP version */ - uint16_t manufacturer; /* Hardware manufacturer name */ - uint16_t lmp_subversion; /* LMP sub-version */ -} __packed hci_read_remote_ver_info_compl_ep; - -#define HCI_EVENT_QOS_SETUP_COMPL 0x0d -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t flags; /* reserved for future use */ - uint8_t service_type; /* service type */ - uint32_t token_rate; /* bytes per second */ - uint32_t peak_bandwidth; /* bytes per second */ - uint32_t latency; /* microseconds */ - uint32_t delay_variation; /* microseconds */ -} __packed hci_qos_setup_compl_ep; - -#define HCI_EVENT_COMMAND_COMPL 0x0e -typedef struct { - uint8_t num_cmd_pkts; /* # of HCI command packets */ - uint16_t opcode; /* command OpCode */ - /* command return parameters (if any) */ -} __packed hci_command_compl_ep; - -#define HCI_EVENT_COMMAND_STATUS 0x0f -typedef struct { - uint8_t status; /* 0x00 - pending */ - uint8_t num_cmd_pkts; /* # of HCI command packets */ - uint16_t opcode; /* command OpCode */ -} __packed hci_command_status_ep; - -#define HCI_EVENT_HARDWARE_ERROR 0x10 -typedef struct { - uint8_t hardware_code; /* hardware error code */ -} __packed hci_hardware_error_ep; - -#define HCI_EVENT_FLUSH_OCCUR 0x11 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_flush_occur_ep; - -#define HCI_EVENT_ROLE_CHANGE 0x12 -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* address of remote unit */ - uint8_t role; /* new connection role */ -} __packed hci_role_change_ep; - -#define HCI_EVENT_NUM_COMPL_PKTS 0x13 -typedef struct { - uint8_t num_con_handles; /* # of connection handles */ -/* these are repeated "num_con_handles" times - uint16_t con_handle; --- connection handle(s) - uint16_t compl_pkts; --- # of completed packets */ -} __packed hci_num_compl_pkts_ep; - -#define HCI_EVENT_MODE_CHANGE 0x14 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t unit_mode; /* remote unit mode */ - uint16_t interval; /* interval * 0.625 msec */ -} __packed hci_mode_change_ep; - -#define HCI_EVENT_RETURN_LINK_KEYS 0x15 -typedef struct { - uint8_t num_keys; /* # of keys */ -/* these are repeated "num_keys" times - bdaddr_t bdaddr; --- remote address(es) - uint8_t key[HCI_KEY_SIZE]; --- key(s) */ -} __packed hci_return_link_keys_ep; - -#define HCI_EVENT_PIN_CODE_REQ 0x16 -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ -} __packed hci_pin_code_req_ep; - -#define HCI_EVENT_LINK_KEY_REQ 0x17 -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ -} __packed hci_link_key_req_ep; - -#define HCI_EVENT_LINK_KEY_NOTIFICATION 0x18 -typedef struct { - bdaddr_t bdaddr; /* remote unit address */ - uint8_t key[HCI_KEY_SIZE]; /* link key */ - uint8_t key_type; /* type of the key */ -} __packed hci_link_key_notification_ep; - -#define HCI_EVENT_LOOPBACK_COMMAND 0x19 -typedef hci_cmd_hdr_t hci_loopback_command_ep; - -#define HCI_EVENT_DATA_BUFFER_OVERFLOW 0x1a -typedef struct { - uint8_t link_type; /* Link type */ -} __packed hci_data_buffer_overflow_ep; - -#define HCI_EVENT_MAX_SLOT_CHANGE 0x1b -typedef struct { - uint16_t con_handle; /* connection handle */ - uint8_t lmp_max_slots; /* Max. # of slots allowed */ -} __packed hci_max_slot_change_ep; - -#define HCI_EVENT_READ_CLOCK_OFFSET_COMPL 0x1c -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* Connection handle */ - uint16_t clock_offset; /* Clock offset */ -} __packed hci_read_clock_offset_compl_ep; - -#define HCI_EVENT_CON_PKT_TYPE_CHANGED 0x1d -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t pkt_type; /* packet type */ -} __packed hci_con_pkt_type_changed_ep; - -#define HCI_EVENT_QOS_VIOLATION 0x1e -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_qos_violation_ep; - -/* Page Scan Mode Change Event is deprecated */ -#define HCI_EVENT_PAGE_SCAN_MODE_CHANGE 0x1f -typedef struct { - bdaddr_t bdaddr; /* destination address */ - uint8_t page_scan_mode; /* page scan mode */ -} __packed hci_page_scan_mode_change_ep; - -#define HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE 0x20 -typedef struct { - bdaddr_t bdaddr; /* destination address */ - uint8_t page_scan_rep_mode; /* page scan repetition mode */ -} __packed hci_page_scan_rep_mode_change_ep; - -#define HCI_EVENT_FLOW_SPECIFICATION_COMPL 0x21 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t flags; /* reserved */ - uint8_t direction; /* flow direction */ - uint8_t type; /* service type */ - uint32_t token_rate; /* token rate */ - uint32_t bucket_size; /* token bucket size */ - uint32_t peak_bandwidth; /* peak bandwidth */ - uint32_t latency; /* access latency */ -} __packed hci_flow_specification_compl_ep; - -#define HCI_EVENT_RSSI_RESULT 0x22 -typedef struct { - uint8_t num_responses; /* number of responses */ -/* hci_rssi_response[num_responses] -- see below */ -} __packed hci_rssi_result_ep; - -typedef struct { - bdaddr_t bdaddr; /* unit address */ - uint8_t page_scan_rep_mode; /* page scan rep. mode */ - uint8_t blank; /* reserved */ - uint8_t uclass[HCI_CLASS_SIZE]; /* unit class */ - uint16_t clock_offset; /* clock offset */ - int8_t rssi; /* rssi */ -} __packed hci_rssi_response; - -#define HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES 0x23 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t page; /* page number */ - uint8_t max; /* max page number */ - uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ -} __packed hci_read_remote_extended_features_ep; - -#define HCI_EVENT_SCO_CON_COMPL 0x2c -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - bdaddr_t bdaddr; /* unit address */ - uint8_t link_type; /* link type */ - uint8_t interval; /* transmission interval */ - uint8_t window; /* retransmission window */ - uint16_t rxlen; /* rx packet length */ - uint16_t txlen; /* tx packet length */ - uint8_t mode; /* air mode */ -} __packed hci_sco_con_compl_ep; - -#define HCI_EVENT_SCO_CON_CHANGED 0x2d -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint8_t interval; /* transmission interval */ - uint8_t window; /* retransmission window */ - uint16_t rxlen; /* rx packet length */ - uint16_t txlen; /* tx packet length */ -} __packed hci_sco_con_changed_ep; - -#define HCI_EVENT_SNIFF_SUBRATING 0x2e -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ - uint16_t tx_latency; /* max transmit latency */ - uint16_t rx_latency; /* max receive latency */ - uint16_t remote_timeout; /* remote timeout */ - uint16_t local_timeout; /* local timeout */ -} __packed hci_sniff_subrating_ep; - -#define HCI_EVENT_EXTENDED_RESULT 0x2f -typedef struct { - uint8_t num_responses; /* must be 0x01 */ - bdaddr_t bdaddr; /* remote device address */ - uint8_t page_scan_rep_mode; - uint8_t reserved; - uint8_t uclass[HCI_CLASS_SIZE]; - uint16_t clock_offset; - int8_t rssi; - uint8_t response[240]; /* extended inquiry response */ -} __packed hci_extended_result_ep; - -#define HCI_EVENT_ENCRYPTION_KEY_REFRESH 0x30 -typedef struct { - uint8_t status; /* 0x00 - success */ - uint16_t con_handle; /* connection handle */ -} __packed hci_encryption_key_refresh_ep; - -#define HCI_EVENT_IO_CAPABILITY_REQ 0x31 -typedef struct { - bdaddr_t bdaddr; /* remote device address */ -} __packed hci_io_capability_req_ep; - -#define HCI_EVENT_IO_CAPABILITY_RSP 0x32 -typedef struct { - bdaddr_t bdaddr; /* remote device address */ - uint8_t io_capability; - uint8_t oob_data_present; - uint8_t auth_requirement; -} __packed hci_io_capability_rsp_ep; - -#define HCI_EVENT_USER_CONFIRM_REQ 0x33 -typedef struct { - bdaddr_t bdaddr; /* remote device address */ - uint32_t value; /* 000000 - 999999 */ -} __packed hci_user_confirm_req_ep; - -#define HCI_EVENT_USER_PASSKEY_REQ 0x34 -typedef struct { - bdaddr_t bdaddr; /* remote device address */ -} __packed hci_user_passkey_req_ep; - -#define HCI_EVENT_REMOTE_OOB_DATA_REQ 0x35 -typedef struct { - bdaddr_t bdaddr; /* remote device address */ -} __packed hci_remote_oob_data_req_ep; - -#define HCI_EVENT_SIMPLE_PAIRING_COMPL 0x36 -typedef struct { - uint8_t status; /* 0x00 - success */ - bdaddr_t bdaddr; /* remote device address */ -} __packed hci_simple_pairing_compl_ep; - -#define HCI_EVENT_LINK_SUPERVISION_TO_CHANGED 0x38 -typedef struct { - uint16_t con_handle; /* connection handle */ - uint16_t timeout; /* link supervision timeout */ -} __packed hci_link_supervision_to_changed_ep; - -#define HCI_EVENT_ENHANCED_FLUSH_COMPL 0x39 -typedef struct { - uint16_t con_handle; /* connection handle */ -} __packed hci_enhanced_flush_compl_ep; - -#define HCI_EVENT_USER_PASSKEY_NOTIFICATION 0x3b -typedef struct { - bdaddr_t bdaddr; /* remote device address */ - uint32_t value; /* 000000 - 999999 */ -} __packed hci_user_passkey_notification_ep; - -#define HCI_EVENT_KEYPRESS_NOTIFICATION 0x3c -typedef struct { - bdaddr_t bdaddr; /* remote device address */ - uint8_t notification_type; -} __packed hci_keypress_notification_ep; - -#define HCI_EVENT_REMOTE_FEATURES_NOTIFICATION 0x3d -typedef struct { - bdaddr_t bdaddr; /* remote device address */ - uint8_t features[HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ -} __packed hci_remote_features_notification_ep; - -#define HCI_EVENT_BT_LOGO 0xfe - -#define HCI_EVENT_VENDOR 0xff - -/************************************************************************** - ************************************************************************** - ** HCI Socket Definitions - ************************************************************************** - **************************************************************************/ - -/* HCI socket options */ -#define SO_HCI_EVT_FILTER 1 /* get/set event filter */ -#define SO_HCI_PKT_FILTER 2 /* get/set packet filter */ -#define SO_HCI_DIRECTION 3 /* packet direction indicator */ - -/* Control Messages */ -#define SCM_HCI_DIRECTION SO_HCI_DIRECTION - -/* - * HCI socket filter and get/set routines - * - * for ease of use, we filter 256 possible events/packets - */ -struct hci_filter { - uint32_t mask[8]; /* 256 bits */ -}; - -static __inline void -hci_filter_set(uint8_t bit, struct hci_filter *filter) -{ - uint8_t off = bit - 1; - - off >>= 5; - filter->mask[off] |= (1 << ((bit - 1) & 0x1f)); -} - -static __inline void -hci_filter_clr(uint8_t bit, struct hci_filter *filter) -{ - uint8_t off = bit - 1; - - off >>= 5; - filter->mask[off] &= ~(1 << ((bit - 1) & 0x1f)); -} - -static __inline int -hci_filter_test(uint8_t bit, struct hci_filter *filter) -{ - uint8_t off = bit - 1; - - off >>= 5; - return (filter->mask[off] & (1 << ((bit - 1) & 0x1f))); -} - -/* - * HCI socket ioctl's - * - * Apart from GBTINFOA, these are all indexed on the unit name - */ - -#define SIOCGBTINFO _IOWR('b', 5, struct btreq) /* get unit info */ -#define SIOCGBTINFOA _IOWR('b', 6, struct btreq) /* get info by address */ -#define SIOCNBTINFO _IOWR('b', 7, struct btreq) /* next unit info */ - -#define SIOCSBTFLAGS _IOWR('b', 8, struct btreq) /* set unit flags */ -#define SIOCSBTPOLICY _IOWR('b', 9, struct btreq) /* set unit link policy */ -#define SIOCSBTPTYPE _IOWR('b', 10, struct btreq) /* set unit packet type */ - -#define SIOCGBTSTATS _IOWR('b', 11, struct btreq) /* get unit statistics */ -#define SIOCZBTSTATS _IOWR('b', 12, struct btreq) /* zero unit statistics */ - -#define SIOCBTDUMP _IOW('b', 13, struct btreq) /* print debug info */ -#define SIOCSBTSCOMTU _IOWR('b', 17, struct btreq) /* set sco_mtu value */ - -struct bt_stats { - uint32_t err_tx; - uint32_t err_rx; - uint32_t cmd_tx; - uint32_t evt_rx; - uint32_t acl_tx; - uint32_t acl_rx; - uint32_t sco_tx; - uint32_t sco_rx; - uint32_t byte_tx; - uint32_t byte_rx; -}; - -struct btreq { - char btr_name[HCI_DEVNAME_SIZE]; /* device name */ - - union { - struct { - bdaddr_t btri_bdaddr; /* device bdaddr */ - uint16_t btri_flags; /* flags */ - uint16_t btri_num_cmd; /* # of free cmd buffers */ - uint16_t btri_num_acl; /* # of free ACL buffers */ - uint16_t btri_num_sco; /* # of free SCO buffers */ - uint16_t btri_acl_mtu; /* ACL mtu */ - uint16_t btri_sco_mtu; /* SCO mtu */ - uint16_t btri_link_policy; /* Link Policy */ - uint16_t btri_packet_type; /* Packet Type */ - } btri; - struct bt_stats btrs; /* unit stats */ - } btru; -}; - -#define btr_flags btru.btri.btri_flags -#define btr_bdaddr btru.btri.btri_bdaddr -#define btr_num_cmd btru.btri.btri_num_cmd -#define btr_num_acl btru.btri.btri_num_acl -#define btr_num_sco btru.btri.btri_num_sco -#define btr_acl_mtu btru.btri.btri_acl_mtu -#define btr_sco_mtu btru.btri.btri_sco_mtu -#define btr_link_policy btru.btri.btri_link_policy -#define btr_packet_type btru.btri.btri_packet_type -#define btr_stats btru.btrs - -/* hci_unit & btr_flags */ -#define BTF_UP (1<<0) /* unit is up */ -#define BTF_RUNNING (1<<1) /* unit is running */ -#define BTF_XMIT_CMD (1<<2) /* unit is transmitting CMD packets */ -#define BTF_XMIT_ACL (1<<3) /* unit is transmitting ACL packets */ -#define BTF_XMIT_SCO (1<<4) /* unit is transmitting SCO packets */ -#define BTF_XMIT (BTF_XMIT_CMD | BTF_XMIT_ACL | BTF_XMIT_SCO) -#define BTF_INIT_BDADDR (1<<5) /* waiting for bdaddr */ -#define BTF_INIT_BUFFER_SIZE (1<<6) /* waiting for buffer size */ -#define BTF_INIT_FEATURES (1<<7) /* waiting for features */ -#define BTF_POWER_UP_NOOP (1<<8) /* should wait for No-op on power up */ -#define BTF_INIT_COMMANDS (1<<9) /* waiting for supported commands */ - -#define BTF_INIT (BTF_INIT_BDADDR \ - | BTF_INIT_BUFFER_SIZE \ - | BTF_INIT_FEATURES \ - | BTF_INIT_COMMANDS) - -/************************************************************************** - ************************************************************************** - ** HCI Kernel Definitions - ************************************************************************** - **************************************************************************/ - -#ifdef _KERNEL - -#include <sys/device.h> -#include <net/if.h> /* for struct ifqueue */ - -struct l2cap_channel; -struct mbuf; -struct sco_pcb; -struct socket; - -/* global HCI kernel variables */ - -/* sysctl variables */ -extern int hci_memo_expiry; -extern int hci_acl_expiry; -extern int hci_sendspace, hci_recvspace; -extern int hci_eventq_max, hci_aclrxq_max, hci_scorxq_max; - -/* - * HCI Connection Information - */ -struct hci_link { - struct hci_unit *hl_unit; /* our unit */ - TAILQ_ENTRY(hci_link) hl_next; /* next link on unit */ - - /* common info */ - uint16_t hl_state; /* connection state */ - uint16_t hl_flags; /* link flags */ - bdaddr_t hl_bdaddr; /* dest address */ - uint16_t hl_handle; /* connection handle */ - uint8_t hl_type; /* link type */ - - /* ACL link info */ - uint8_t hl_lastid; /* last id used */ - uint16_t hl_refcnt; /* reference count */ - uint16_t hl_mtu; /* signalling mtu for link */ - uint16_t hl_flush; /* flush timeout */ - uint16_t hl_clock; /* remote clock offset */ - - TAILQ_HEAD(,l2cap_pdu) hl_txq; /* queue of outgoing PDUs */ - int hl_txqlen; /* number of fragments */ - struct mbuf *hl_rxp; /* incoming PDU (accumulating)*/ - struct timeout hl_expire; /* connection expiry timer */ - TAILQ_HEAD(,l2cap_req) hl_reqs; /* pending requests */ - - /* SCO link info */ - struct hci_link *hl_link; /* SCO ACL link */ - struct sco_pcb *hl_sco; /* SCO pcb */ - struct ifqueue hl_data; /* SCO outgoing data */ -}; - -/* hci_link state */ -#define HCI_LINK_CLOSED 0 /* closed */ -#define HCI_LINK_WAIT_CONNECT 1 /* waiting to connect */ -#define HCI_LINK_WAIT_AUTH 2 /* waiting for auth */ -#define HCI_LINK_WAIT_ENCRYPT 3 /* waiting for encrypt */ -#define HCI_LINK_WAIT_SECURE 4 /* waiting for secure */ -#define HCI_LINK_OPEN 5 /* ready and willing */ -#define HCI_LINK_BLOCK 6 /* open but blocking (see hci_acl_start) */ - -/* hci_link flags */ -#define HCI_LINK_AUTH_REQ (1<<0) /* authentication requested */ -#define HCI_LINK_ENCRYPT_REQ (1<<1) /* encryption requested */ -#define HCI_LINK_SECURE_REQ (1<<2) /* secure link requested */ -#define HCI_LINK_AUTH (1<<3) /* link is authenticated */ -#define HCI_LINK_ENCRYPT (1<<4) /* link is encrypted */ -#define HCI_LINK_SECURE (1<<5) /* link is secured */ -#define HCI_LINK_CREATE_CON (1<<6) /* "Create Connection" pending */ - -/* - * Bluetooth Memo - * cached device information for remote devices that this unit has seen - */ -struct hci_memo { - struct timeval time; /* time of last response */ - bdaddr_t bdaddr; - uint8_t page_scan_rep_mode; - uint8_t page_scan_mode; - uint16_t clock_offset; - LIST_ENTRY(hci_memo) next; -}; - -/* - * The Bluetooth HCI interface attachment structure - */ -struct hci_if { - int (*enable)(struct device *); - void (*disable)(struct device *); - void (*output_cmd)(struct device *, struct mbuf *); - void (*output_acl)(struct device *, struct mbuf *); - void (*output_sco)(struct device *, struct mbuf *); - void (*get_stats)(struct device *, struct bt_stats *, int); - int ipl; /* for locking */ -}; - -/* - * The Bluetooth HCI device unit structure - */ -struct hci_unit { - struct device *hci_dev; /* bthci handle */ - struct device *hci_bthub; /* bthub(4) handle */ - const struct hci_if *hci_if; /* bthci driver interface */ - - /* device info */ - bdaddr_t hci_bdaddr; /* device address */ - uint16_t hci_flags; /* see BTF_ above */ - int hci_init; /* sleep on this */ - - uint16_t hci_packet_type; /* packet types */ - uint16_t hci_acl_mask; /* ACL packet capabilities */ - uint16_t hci_sco_mask; /* SCO packet capabilities */ - - uint16_t hci_link_policy; /* link policy */ - uint16_t hci_lmp_mask; /* link policy capabilities */ - - uint8_t hci_cmds[HCI_COMMANDS_SIZE]; /* opcode bitmask */ - - /* flow control */ - uint16_t hci_max_acl_size; /* ACL payload mtu */ - uint16_t hci_num_acl_pkts; /* free ACL packet buffers */ - uint8_t hci_num_cmd_pkts; /* free CMD packet buffers */ - uint8_t hci_max_sco_size; /* SCO payload mtu */ - uint16_t hci_num_sco_pkts; /* free SCO packet buffers */ - - TAILQ_HEAD(,hci_link) hci_links; /* list of ACL/SCO links */ - LIST_HEAD(,hci_memo) hci_memos; /* cached memo list */ - - /* input queues */ -#ifndef __OpenBSD__ - void *hci_rxint; /* receive interrupt cookie */ -#endif - struct mutex hci_devlock; /* device queue lock */ - struct ifqueue hci_eventq; /* Event queue */ - struct ifqueue hci_aclrxq; /* ACL rx queue */ - struct ifqueue hci_scorxq; /* SCO rx queue */ - uint16_t hci_eventqlen; /* Event queue length */ - uint16_t hci_aclrxqlen; /* ACL rx queue length */ - uint16_t hci_scorxqlen; /* SCO rx queue length */ - - /* output queues */ - struct ifqueue hci_cmdwait; /* pending commands */ - struct ifqueue hci_scodone; /* SCO done queue */ - - TAILQ_ENTRY(hci_unit) hci_next; -}; - -extern TAILQ_HEAD(hci_unit_list, hci_unit) hci_unit_list; - -/* - * HCI layer function prototypes - */ - -/* hci_event.c */ -void hci_event(struct mbuf *, struct hci_unit *); - -/* hci_ioctl.c */ -int hci_ioctl(unsigned long, void *, struct proc *); - -/* hci_link.c */ -struct hci_link *hci_acl_open(struct hci_unit *, bdaddr_t *); -struct hci_link *hci_acl_newconn(struct hci_unit *, bdaddr_t *); -void hci_acl_close(struct hci_link *, int); -void hci_acl_timeout(void *); -int hci_acl_setmode(struct hci_link *); -void hci_acl_linkmode(struct hci_link *); -void hci_acl_recv(struct mbuf *, struct hci_unit *); -int hci_acl_send(struct mbuf *, struct hci_link *, struct l2cap_channel *); -void hci_acl_start(struct hci_link *); -void hci_acl_complete(struct hci_link *, int); -struct hci_link *hci_sco_newconn(struct hci_unit *, bdaddr_t *); -void hci_sco_recv(struct mbuf *, struct hci_unit *); -void hci_sco_start(struct hci_link *); -void hci_sco_complete(struct hci_link *, int); -struct hci_link *hci_link_alloc(struct hci_unit *, bdaddr_t *, uint8_t); -void hci_link_free(struct hci_link *, int); -struct hci_link *hci_link_lookup_bdaddr(struct hci_unit *, bdaddr_t *, uint8_t); -struct hci_link *hci_link_lookup_handle(struct hci_unit *, uint16_t); - -/* hci_misc.c */ -int hci_route_lookup(bdaddr_t *, bdaddr_t *); -struct hci_memo *hci_memo_find(struct hci_unit *, bdaddr_t *); -struct hci_memo *hci_memo_new(struct hci_unit *, bdaddr_t *); -void hci_memo_free(struct hci_memo *); - -/* hci_socket.c */ -void hci_drop(void *); -int hci_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, - struct mbuf *, struct proc *); -int hci_ctloutput(int, struct socket *, int, int, struct mbuf **); -void hci_mtap(struct mbuf *, struct hci_unit *); - -/* hci_unit.c */ -struct hci_unit *hci_attach(const struct hci_if *, struct device *, uint16_t); -void hci_detach(struct hci_unit *); -int hci_enable(struct hci_unit *); -void hci_disable(struct hci_unit *); -struct hci_unit *hci_unit_lookup(bdaddr_t *); -int hci_send_cmd(struct hci_unit *, uint16_t, void *, uint8_t); -void hci_num_cmds(struct hci_unit *, uint8_t); -int hci_input_event(struct hci_unit *, struct mbuf *); -int hci_input_acl(struct hci_unit *, struct mbuf *); -int hci_input_sco(struct hci_unit *, struct mbuf *); -int hci_complete_sco(struct hci_unit *, struct mbuf *); -void hci_output_cmd(struct hci_unit *, struct mbuf *); -void hci_output_acl(struct hci_unit *, struct mbuf *); -void hci_output_sco(struct hci_unit *, struct mbuf *); -void hci_intr(void *); - -/* XXX mimic NetBSD for now, although we don't have these interfaces */ -#define M_GETCTX(m, t) ((t)(m)->m_pkthdr.rcvif) -#define M_SETCTX(m, c) ((m)->m_pkthdr.rcvif = (void *)(c)) -#define splraiseipl(ipl) splbio() /* XXX */ -#define ENOLINK ENOENT /* XXX */ -#define EPASSTHROUGH ENOTTY /* XXX */ -#define device_xname(dv) (dv)->dv_xname - -#endif /* _KERNEL */ - -#endif /* _NETBT_HCI_H_ */ diff --git a/sys/netbt/hci_event.c b/sys/netbt/hci_event.c deleted file mode 100644 index 4715d3cf665..00000000000 --- a/sys/netbt/hci_event.c +++ /dev/null @@ -1,1112 +0,0 @@ -/* $OpenBSD: hci_event.c,v 1.9 2010/08/20 17:00:40 jsg Exp $ */ -/* $NetBSD: hci_event.c,v 1.18 2008/04/24 11:38:37 ad Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/sco.h> - -static void hci_event_inquiry_result(struct hci_unit *, struct mbuf *); -static void hci_event_rssi_result(struct hci_unit *, struct mbuf *); -static void hci_event_command_status(struct hci_unit *, struct mbuf *); -static void hci_event_command_compl(struct hci_unit *, struct mbuf *); -static void hci_event_con_compl(struct hci_unit *, struct mbuf *); -static void hci_event_discon_compl(struct hci_unit *, struct mbuf *); -static void hci_event_con_req(struct hci_unit *, struct mbuf *); -static void hci_event_num_compl_pkts(struct hci_unit *, struct mbuf *); -static void hci_event_auth_compl(struct hci_unit *, struct mbuf *); -static void hci_event_encryption_change(struct hci_unit *, struct mbuf *); -static void hci_event_change_con_link_key_compl(struct hci_unit *, struct mbuf *); -static void hci_event_read_clock_offset_compl(struct hci_unit *, struct mbuf *); -static void hci_cmd_read_bdaddr(struct hci_unit *, struct mbuf *); -static void hci_cmd_read_buffer_size(struct hci_unit *, struct mbuf *); -static void hci_cmd_read_local_features(struct hci_unit *, struct mbuf *); -static void hci_cmd_read_local_ver(struct hci_unit *, struct mbuf *); -static void hci_cmd_read_local_commands(struct hci_unit *, struct mbuf *); -static void hci_cmd_reset(struct hci_unit *, struct mbuf *); -static void hci_cmd_create_con(struct hci_unit *unit, uint8_t status); - -#ifdef BLUETOOTH_DEBUG -int bluetooth_debug; - -static const char *hci_eventnames[] = { -/* 0x00 */ "NULL", -/* 0x01 */ "INQUIRY COMPLETE", -/* 0x02 */ "INQUIRY RESULT", -/* 0x03 */ "CONN COMPLETE", -/* 0x04 */ "CONN REQ", -/* 0x05 */ "DISCONN COMPLETE", -/* 0x06 */ "AUTH COMPLETE", -/* 0x07 */ "REMOTE NAME REQ COMPLETE", -/* 0x08 */ "ENCRYPTION CHANGE", -/* 0x09 */ "CHANGE CONN LINK KEY COMPLETE", -/* 0x0a */ "MASTER LINK KEY COMPLETE", -/* 0x0b */ "READ REMOTE FEATURES COMPLETE", -/* 0x0c */ "READ REMOTE VERSION INFO COMPLETE", -/* 0x0d */ "QoS SETUP COMPLETE", -/* 0x0e */ "COMMAND COMPLETE", -/* 0x0f */ "COMMAND STATUS", -/* 0x10 */ "HARDWARE ERROR", -/* 0x11 */ "FLUSH OCCUR", -/* 0x12 */ "ROLE CHANGE", -/* 0x13 */ "NUM COMPLETED PACKETS", -/* 0x14 */ "MODE CHANGE", -/* 0x15 */ "RETURN LINK KEYS", -/* 0x16 */ "PIN CODE REQ", -/* 0x17 */ "LINK KEY REQ", -/* 0x18 */ "LINK KEY NOTIFICATION", -/* 0x19 */ "LOOPBACK COMMAND", -/* 0x1a */ "DATA BUFFER OVERFLOW", -/* 0x1b */ "MAX SLOT CHANGE", -/* 0x1c */ "READ CLOCK OFFSET COMPLETE", -/* 0x1d */ "CONN PKT TYPE CHANGED", -/* 0x1e */ "QOS VIOLATION", -/* 0x1f */ "PAGE SCAN MODE CHANGE", -/* 0x20 */ "PAGE SCAN REP MODE CHANGE", -/* 0x21 */ "FLOW SPECIFICATION COMPLETE", -/* 0x22 */ "RSSI RESULT", -/* 0x23 */ "READ REMOTE EXT FEATURES", -/* 0x24 */ "UNKNOWN", -/* 0x25 */ "UNKNOWN", -/* 0x26 */ "UNKNOWN", -/* 0x27 */ "UNKNOWN", -/* 0x28 */ "UNKNOWN", -/* 0x29 */ "UNKNOWN", -/* 0x2a */ "UNKNOWN", -/* 0x2b */ "UNKNOWN", -/* 0x2c */ "SCO CON COMPLETE", -/* 0x2d */ "SCO CON CHANGED", -/* 0x2e */ "SNIFF SUBRATING", -/* 0x2f */ "EXTENDED INQUIRY RESULT", -/* 0x30 */ "ENCRYPTION KEY REFRESH", -/* 0x31 */ "IO CAPABILITY REQUEST", -/* 0x32 */ "IO CAPABILITY RESPONSE", -/* 0x33 */ "USER CONFIRM REQUEST", -/* 0x34 */ "USER PASSKEY REQUEST", -/* 0x35 */ "REMOTE OOB DATA REQUEST", -/* 0x36 */ "SIMPLE PAIRING COMPLETE", -/* 0x37 */ "UNKNOWN", -/* 0x38 */ "LINK SUPERVISION TIMEOUT CHANGED", -/* 0x39 */ "ENHANCED FLUSH COMPLETE", -/* 0x3a */ "UNKNOWN", -/* 0x3b */ "USER PASSKEY NOTIFICATION", -/* 0x3c */ "KEYPRESS NOTIFICATION", -/* 0x3d */ "REMOTE HOST FEATURES NOTIFICATION", -}; - -static const char * -hci_eventstr(unsigned int event) -{ - - if (event < (sizeof(hci_eventnames) / sizeof(*hci_eventnames))) - return hci_eventnames[event]; - - switch (event) { - case HCI_EVENT_BT_LOGO: /* 0xfe */ - return "BT_LOGO"; - - case HCI_EVENT_VENDOR: /* 0xff */ - return "VENDOR"; - } - - return "UNKNOWN"; -} -#endif /* BLUETOOTH_DEBUG */ - -/* - * process HCI Events - * - * We will free the mbuf at the end, no need for any sub - * functions to handle that. We kind of assume that the - * device sends us valid events. - */ -void -hci_event(struct mbuf *m, struct hci_unit *unit) -{ - hci_event_hdr_t hdr; - - KASSERT(m->m_flags & M_PKTHDR); - - KASSERT(m->m_pkthdr.len >= sizeof(hdr)); - m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); - m_adj(m, sizeof(hdr)); - - KASSERT(hdr.type == HCI_EVENT_PKT); - - DPRINTFN(1, "(%s) event %s\n", - device_xname(unit->hci_dev), hci_eventstr(hdr.event)); - - switch(hdr.event) { - case HCI_EVENT_COMMAND_STATUS: - hci_event_command_status(unit, m); - break; - - case HCI_EVENT_COMMAND_COMPL: - hci_event_command_compl(unit, m); - break; - - case HCI_EVENT_NUM_COMPL_PKTS: - hci_event_num_compl_pkts(unit, m); - break; - - case HCI_EVENT_INQUIRY_RESULT: - hci_event_inquiry_result(unit, m); - break; - - case HCI_EVENT_RSSI_RESULT: - hci_event_rssi_result(unit, m); - break; - - case HCI_EVENT_CON_COMPL: - hci_event_con_compl(unit, m); - break; - - case HCI_EVENT_DISCON_COMPL: - hci_event_discon_compl(unit, m); - break; - - case HCI_EVENT_CON_REQ: - hci_event_con_req(unit, m); - break; - - case HCI_EVENT_AUTH_COMPL: - hci_event_auth_compl(unit, m); - break; - - case HCI_EVENT_ENCRYPTION_CHANGE: - hci_event_encryption_change(unit, m); - break; - - case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL: - hci_event_change_con_link_key_compl(unit, m); - break; - - case HCI_EVENT_READ_CLOCK_OFFSET_COMPL: - hci_event_read_clock_offset_compl(unit, m); - break; - - default: - break; - } - - m_freem(m); -} - -/* - * Command Status - * - * Restart command queue and post-process any pending commands - */ -static void -hci_event_command_status(struct hci_unit *unit, struct mbuf *m) -{ - hci_command_status_ep ep; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - ep.opcode = letoh16(ep.opcode); - - DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n", - device_xname(unit->hci_dev), - HCI_OGF(ep.opcode), HCI_OCF(ep.opcode), - ep.status, - ep.num_cmd_pkts); - - hci_num_cmds(unit, ep.num_cmd_pkts); - - /* - * post processing of pending commands - */ - switch(ep.opcode) { - case HCI_CMD_CREATE_CON: - hci_cmd_create_con(unit, ep.status); - break; - - default: - if (ep.status == 0) - break; - - DPRINTFN(1, - "(%s) CommandStatus opcode (%03x|%04x)" - " failed (status=0x%02x)\n", - device_xname(unit->hci_dev), - HCI_OGF(ep.opcode), HCI_OCF(ep.opcode), - ep.status); - - break; - } -} - -/* - * Command Complete - * - * Restart command queue and handle the completed command - */ -static void -hci_event_command_compl(struct hci_unit *unit, struct mbuf *m) -{ - hci_command_compl_ep ep; - hci_status_rp rp; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - DPRINTFN(1, "(%s) opcode (%03x|%04x) num_cmd_pkts = %d\n", - device_xname(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)), - HCI_OCF(letoh16(ep.opcode)), ep.num_cmd_pkts); - - hci_num_cmds(unit, ep.num_cmd_pkts); - - /* - * I am not sure if this is completely correct, it is not guaranteed - * that a command_complete packet will contain the status though most - * do seem to. - */ - m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); - if (rp.status > 0) - printf("%s: CommandComplete opcode (%03x|%04x) failed (status=0x%02x)\n", - device_xname(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)), - HCI_OCF(letoh16(ep.opcode)), rp.status); - - /* - * post processing of completed commands - */ - switch(letoh16(ep.opcode)) { - case HCI_CMD_READ_BDADDR: - hci_cmd_read_bdaddr(unit, m); - break; - - case HCI_CMD_READ_BUFFER_SIZE: - hci_cmd_read_buffer_size(unit, m); - break; - - case HCI_CMD_READ_LOCAL_FEATURES: - hci_cmd_read_local_features(unit, m); - break; - - case HCI_CMD_READ_LOCAL_VER: - hci_cmd_read_local_ver(unit, m); - break; - - case HCI_CMD_READ_LOCAL_COMMANDS: - hci_cmd_read_local_commands(unit, m); - break; - - case HCI_CMD_RESET: - hci_cmd_reset(unit, m); - break; - - default: - break; - } -} - -/* - * Number of Completed Packets - * - * This is sent periodically by the Controller telling us how many - * buffers are now freed up and which handle was using them. From - * this we determine which type of buffer it was and add the qty - * back into the relevant packet counter, then restart output on - * links that have halted. - */ -static void -hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m) -{ - hci_num_compl_pkts_ep ep; - struct hci_link *link, *next; - uint16_t handle, num; - int num_acl = 0, num_sco = 0; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - while (ep.num_con_handles--) { - m_copydata(m, 0, sizeof(handle), (caddr_t)&handle); - m_adj(m, sizeof(handle)); - handle = letoh16(handle); - - m_copydata(m, 0, sizeof(num), (caddr_t)&num); - m_adj(m, sizeof(num)); - num = letoh16(num); - - link = hci_link_lookup_handle(unit, handle); - if (link) { - if (link->hl_type == HCI_LINK_ACL) { - num_acl += num; - hci_acl_complete(link, num); - } else { - num_sco += num; - hci_sco_complete(link, num); - } - } else { - /* XXX need to issue Read_Buffer_Size or Reset? */ - printf("%s: unknown handle %d! " - "(losing track of %d packet buffer%s)\n", - device_xname(unit->hci_dev), handle, - num, (num == 1 ? "" : "s")); - } - } - - /* - * Move up any queued packets. When a link has sent data, it will move - * to the back of the queue - technically then if a link had something - * to send and there were still buffers available it could get started - * twice but it seemed more important to to handle higher loads fairly - * than worry about wasting cycles when we are not busy. - */ - - unit->hci_num_acl_pkts += num_acl; - unit->hci_num_sco_pkts += num_sco; - - link = TAILQ_FIRST(&unit->hci_links); - while (link && (unit->hci_num_acl_pkts > 0 || unit->hci_num_sco_pkts > 0)) { - next = TAILQ_NEXT(link, hl_next); - - if (link->hl_type == HCI_LINK_ACL) { - if (unit->hci_num_acl_pkts > 0 && link->hl_txqlen > 0) - hci_acl_start(link); - } else { - if (unit->hci_num_sco_pkts > 0 && link->hl_txqlen > 0) - hci_sco_start(link); - } - - link = next; - } -} - -/* - * Inquiry Result - * - * keep a note of devices seen, so we know which unit to use - * on outgoing connections - */ -static void -hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m) -{ - hci_inquiry_result_ep ep; - hci_inquiry_response ir; - struct hci_memo *memo; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - DPRINTFN(1, "(%s) %d response%s\n", device_xname(unit->hci_dev), - ep.num_responses, (ep.num_responses == 1 ? "" : "s")); - - while(ep.num_responses--) { - KASSERT(m->m_pkthdr.len >= sizeof(ir)); - m_copydata(m, 0, sizeof(ir), (caddr_t)&ir); - m_adj(m, sizeof(ir)); - - DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n", - ir.bdaddr.b[5], ir.bdaddr.b[4], ir.bdaddr.b[3], - ir.bdaddr.b[2], ir.bdaddr.b[1], ir.bdaddr.b[0]); - - memo = hci_memo_new(unit, &ir.bdaddr); - if (memo != NULL) { - memo->page_scan_rep_mode = ir.page_scan_rep_mode; - memo->page_scan_mode = ir.page_scan_mode; - memo->clock_offset = ir.clock_offset; - } - } -} - -/* - * Inquiry Result with RSSI - * - * as above but different packet when RSSI result is enabled - */ -static void -hci_event_rssi_result(struct hci_unit *unit, struct mbuf *m) -{ - hci_rssi_result_ep ep; - hci_rssi_response rr; - struct hci_memo *memo; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - DPRINTFN(1, "%d response%s\n", ep.num_responses, - (ep.num_responses == 1 ? "" : "s")); - - while(ep.num_responses--) { - KASSERT(m->m_pkthdr.len >= sizeof(rr)); - m_copydata(m, 0, sizeof(rr), (caddr_t)&rr); - m_adj(m, sizeof(rr)); - - DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n", - rr.bdaddr.b[5], rr.bdaddr.b[4], rr.bdaddr.b[3], - rr.bdaddr.b[2], rr.bdaddr.b[1], rr.bdaddr.b[0]); - - memo = hci_memo_new(unit, &rr.bdaddr); - if (memo != NULL) { - memo->page_scan_rep_mode = rr.page_scan_rep_mode; - memo->page_scan_mode = 0; - memo->clock_offset = rr.clock_offset; - } - } -} - -/* - * Connection Complete - * - * Sent to us when a connection is made. If there is no link - * structure already allocated for this, we must have changed - * our mind, so just disconnect. - */ -static void -hci_event_con_compl(struct hci_unit *unit, struct mbuf *m) -{ - hci_con_compl_ep ep; - hci_write_link_policy_settings_cp cp; - struct hci_link *link; - int err; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - DPRINTFN(1, "(%s) %s connection complete for " - "%02x:%02x:%02x:%02x:%02x:%02x status %#x\n", - device_xname(unit->hci_dev), - (ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"), - ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3], - ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0], - ep.status); - - link = hci_link_lookup_bdaddr(unit, &ep.bdaddr, ep.link_type); - - if (ep.status) { - if (link != NULL) { - switch (ep.status) { - case 0x04: /* "Page Timeout" */ - err = EHOSTDOWN; - break; - - case 0x08: /* "Connection Timed Out" */ - case 0x10: /* "Connection Accept Timeout Exceeded" */ - err = ETIMEDOUT; - break; - - case 0x16: /* "Connection Terminated by Local Host" */ - err = 0; - break; - - default: - err = ECONNREFUSED; - break; - } - - hci_link_free(link, err); - } - - return; - } - - if (link == NULL) { - hci_discon_cp dp; - - dp.con_handle = ep.con_handle; - dp.reason = 0x13; /* "Remote User Terminated Connection" */ - - hci_send_cmd(unit, HCI_CMD_DISCONNECT, &dp, sizeof(dp)); - return; - } - - /* XXX could check auth_enable here */ - - if (ep.encryption_mode) - link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); - - link->hl_state = HCI_LINK_OPEN; - link->hl_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); - - if (ep.link_type == HCI_LINK_ACL) { - cp.con_handle = ep.con_handle; - cp.settings = htole16(unit->hci_link_policy); - err = hci_send_cmd(unit, HCI_CMD_WRITE_LINK_POLICY_SETTINGS, - &cp, sizeof(cp)); - if (err) - printf("%s: Warning, could not write link policy\n", - device_xname(unit->hci_dev)); - - err = hci_send_cmd(unit, HCI_CMD_READ_CLOCK_OFFSET, - &cp.con_handle, sizeof(cp.con_handle)); - if (err) - printf("%s: Warning, could not read clock offset\n", - device_xname(unit->hci_dev)); - - err = hci_acl_setmode(link); - if (err == EINPROGRESS) - return; - - hci_acl_linkmode(link); - } else { - (*link->hl_sco->sp_proto->connected)(link->hl_sco->sp_upper); - } -} - -/* - * Disconnection Complete - * - * This is sent in response to a disconnection request, but also if - * the remote device goes out of range. - */ -static void -hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m) -{ - hci_discon_compl_ep ep; - struct hci_link *link; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - ep.con_handle = letoh16(ep.con_handle); - - DPRINTFN(1, "(%s) handle #%d, status=0x%x\n", - device_xname(unit->hci_dev), ep.con_handle, ep.status); - - link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle)); - if (link) - hci_link_free(link, ENOENT); /* XXX NetBSD used ENOLINK here */ -} - -/* - * Connect Request - * - * We check upstream for appropriate listeners and accept connections - * that are wanted. - */ -static void -hci_event_con_req(struct hci_unit *unit, struct mbuf *m) -{ - hci_con_req_ep ep; - hci_accept_con_cp ap; - hci_reject_con_cp rp; - struct hci_link *link; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - DPRINTFN(1, "(%s) bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " - "class %2.2x%2.2x%2.2x type %s\n", - device_xname(unit->hci_dev), - ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3], - ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0], - ep.uclass[0], ep.uclass[1], ep.uclass[2], - ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"); - - if (ep.link_type == HCI_LINK_ACL) - link = hci_acl_newconn(unit, &ep.bdaddr); - else - link = hci_sco_newconn(unit, &ep.bdaddr); - - if (link == NULL) { - memset(&rp, 0, sizeof(rp)); - bdaddr_copy(&rp.bdaddr, &ep.bdaddr); - rp.reason = 0x0f; /* Unacceptable BD_ADDR */ - - hci_send_cmd(unit, HCI_CMD_REJECT_CON, &rp, sizeof(rp)); - } else { - memset(&ap, 0, sizeof(ap)); - bdaddr_copy(&ap.bdaddr, &ep.bdaddr); - if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH) - ap.role = HCI_ROLE_MASTER; - else - ap.role = HCI_ROLE_SLAVE; - - hci_send_cmd(unit, HCI_CMD_ACCEPT_CON, &ap, sizeof(ap)); - } -} - -/* - * Auth Complete - * - * Authentication has been completed on an ACL link. We can notify the - * upper layer protocols unless further mode changes are pending. - */ -static void -hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m) -{ - hci_auth_compl_ep ep; - struct hci_link *link; - int err; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); - - DPRINTFN(1, "(%s) handle #%d, status=0x%x\n", - device_xname(unit->hci_dev), ep.con_handle, ep.status); - - link = hci_link_lookup_handle(unit, ep.con_handle); - if (link == NULL || link->hl_type != HCI_LINK_ACL) - return; - - if (ep.status == 0) { - link->hl_flags |= HCI_LINK_AUTH; - - if (link->hl_state == HCI_LINK_WAIT_AUTH) - link->hl_state = HCI_LINK_OPEN; - - err = hci_acl_setmode(link); - if (err == EINPROGRESS) - return; - } - - hci_acl_linkmode(link); -} - -/* - * Encryption Change - * - * The encryption status has changed. Basically, we note the change - * then notify the upper layer protocol unless further mode changes - * are pending. - * Note that if encryption gets disabled when it has been requested, - * we will attempt to enable it again.. (its a feature not a bug :) - */ -static void -hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m) -{ - hci_encryption_change_ep ep; - struct hci_link *link; - int err; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); - - DPRINTFN(1, "(%s) handle #%d, status=0x%x, encryption_enable=0x%x\n", - device_xname(unit->hci_dev), ep.con_handle, ep.status, - ep.encryption_enable); - - link = hci_link_lookup_handle(unit, ep.con_handle); - if (link == NULL || link->hl_type != HCI_LINK_ACL) - return; - - if (ep.status == 0) { - if (ep.encryption_enable == 0) - link->hl_flags &= ~HCI_LINK_ENCRYPT; - else - link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); - - if (link->hl_state == HCI_LINK_WAIT_ENCRYPT) - link->hl_state = HCI_LINK_OPEN; - - err = hci_acl_setmode(link); - if (err == EINPROGRESS) - return; - } - - hci_acl_linkmode(link); -} - -/* - * Change Connection Link Key Complete - * - * Link keys are handled in userland but if we are waiting to secure - * this link, we should notify the upper protocols. A SECURE request - * only needs a single key change, so we can cancel the request. - */ -static void -hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m) -{ - hci_change_con_link_key_compl_ep ep; - struct hci_link *link; - int err; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); - - DPRINTFN(1, "(%s) handle #%d, status=0x%x\n", - device_xname(unit->hci_dev), ep.con_handle, ep.status); - - link = hci_link_lookup_handle(unit, ep.con_handle); - if (link == NULL || link->hl_type != HCI_LINK_ACL) - return; - - link->hl_flags &= ~HCI_LINK_SECURE_REQ; - - if (ep.status == 0) { - link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_SECURE); - - if (link->hl_state == HCI_LINK_WAIT_SECURE) - link->hl_state = HCI_LINK_OPEN; - - err = hci_acl_setmode(link); - if (err == EINPROGRESS) - return; - } - - hci_acl_linkmode(link); -} - -/* - * Read Clock Offset Complete - * - * We keep a note of the clock offset of remote devices when a - * link is made, in order to facilitate reconnections to the device - */ -static void -hci_event_read_clock_offset_compl(struct hci_unit *unit, struct mbuf *m) -{ - hci_read_clock_offset_compl_ep ep; - struct hci_link *link; - - KASSERT(m->m_pkthdr.len >= sizeof(ep)); - m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); - m_adj(m, sizeof(ep)); - - DPRINTFN(1, "handle #%d, offset=%u, status=0x%x\n", - letoh16(ep.con_handle), letoh16(ep.clock_offset), ep.status); - - ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); - link = hci_link_lookup_handle(unit, ep.con_handle); - - if (ep.status != 0 || link == NULL) - return; - - link->hl_clock = ep.clock_offset; -} - -/* - * process results of read_bdaddr command_complete event - */ -static void -hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m) -{ - hci_read_bdaddr_rp rp; - - KASSERT(m->m_pkthdr.len >= sizeof(rp)); - m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); - m_adj(m, sizeof(rp)); - - if (rp.status > 0) - return; - - if ((unit->hci_flags & BTF_INIT_BDADDR) == 0) - return; - - bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr); - - unit->hci_flags &= ~BTF_INIT_BDADDR; - - wakeup(&unit->hci_init); -} - -/* - * process results of read_buffer_size command_complete event - */ -static void -hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m) -{ - hci_read_buffer_size_rp rp; - - KASSERT(m->m_pkthdr.len >= sizeof(rp)); - m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); - m_adj(m, sizeof(rp)); - - if (rp.status > 0) - return; - - if ((unit->hci_flags & BTF_INIT_BUFFER_SIZE) == 0) - return; - - unit->hci_max_acl_size = letoh16(rp.max_acl_size); - unit->hci_num_acl_pkts = letoh16(rp.num_acl_pkts); - unit->hci_max_sco_size = rp.max_sco_size; - unit->hci_num_sco_pkts = letoh16(rp.num_sco_pkts); - - unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE; - - wakeup(&unit->hci_init); -} - -/* - * process results of read_local_features command_complete event - */ -static void -hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m) -{ - hci_read_local_features_rp rp; - - KASSERT(m->m_pkthdr.len >= sizeof(rp)); - m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); - m_adj(m, sizeof(rp)); - - if (rp.status > 0) - return; - - if ((unit->hci_flags & BTF_INIT_FEATURES) == 0) - return; - - unit->hci_lmp_mask = 0; - - if (rp.features[0] & HCI_LMP_ROLE_SWITCH) - unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH; - - if (rp.features[0] & HCI_LMP_HOLD_MODE) - unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_HOLD_MODE; - - if (rp.features[0] & HCI_LMP_SNIFF_MODE) - unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE; - - if (rp.features[1] & HCI_LMP_PARK_MODE) - unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_PARK_MODE; - - /* ACL packet mask */ - unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1; - - if (rp.features[0] & HCI_LMP_3SLOT) - unit->hci_acl_mask |= HCI_PKT_DM3 | HCI_PKT_DH3; - - if (rp.features[0] & HCI_LMP_5SLOT) - unit->hci_acl_mask |= HCI_PKT_DM5 | HCI_PKT_DH5; - - if ((rp.features[3] & HCI_LMP_EDR_ACL_2MBPS) == 0) - unit->hci_acl_mask |= HCI_PKT_2MBPS_DH1 - | HCI_PKT_2MBPS_DH3 - | HCI_PKT_2MBPS_DH5; - - if ((rp.features[3] & HCI_LMP_EDR_ACL_3MBPS) == 0) - unit->hci_acl_mask |= HCI_PKT_3MBPS_DH1 - | HCI_PKT_3MBPS_DH3 - | HCI_PKT_3MBPS_DH5; - - if ((rp.features[4] & HCI_LMP_3SLOT_EDR_ACL) == 0) - unit->hci_acl_mask |= HCI_PKT_2MBPS_DH3 - | HCI_PKT_3MBPS_DH3; - - if ((rp.features[5] & HCI_LMP_5SLOT_EDR_ACL) == 0) - unit->hci_acl_mask |= HCI_PKT_2MBPS_DH5 - | HCI_PKT_3MBPS_DH5; - - unit->hci_packet_type = unit->hci_acl_mask; - - /* SCO packet mask */ - unit->hci_sco_mask = 0; - if (rp.features[1] & HCI_LMP_SCO_LINK) - unit->hci_sco_mask |= HCI_PKT_HV1; - - if (rp.features[1] & HCI_LMP_HV2_PKT) - unit->hci_sco_mask |= HCI_PKT_HV2; - - if (rp.features[1] & HCI_LMP_HV3_PKT) - unit->hci_sco_mask |= HCI_PKT_HV3; - - if (rp.features[3] & HCI_LMP_EV3_PKT) - unit->hci_sco_mask |= HCI_PKT_EV3; - - if (rp.features[4] & HCI_LMP_EV4_PKT) - unit->hci_sco_mask |= HCI_PKT_EV4; - - if (rp.features[4] & HCI_LMP_EV5_PKT) - unit->hci_sco_mask |= HCI_PKT_EV5; - - /* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */ - - unit->hci_flags &= ~BTF_INIT_FEATURES; - - wakeup(&unit->hci_init); - - DPRINTFN(1, "%s: lmp_mask %4.4x, acl_mask %4.4x, sco_mask %4.4x\n", - device_xname(unit->hci_dev), unit->hci_lmp_mask, - unit->hci_acl_mask, unit->hci_sco_mask); -} - -/* - * process results of read_local_ver command_complete event - * - * reading local supported commands is only supported from 1.2 spec - */ -static void -hci_cmd_read_local_ver(struct hci_unit *unit, struct mbuf *m) -{ - hci_read_local_ver_rp rp; - - KASSERT(m->m_pkthdr.len >= sizeof(rp)); - m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); - m_adj(m, sizeof(rp)); - - if (rp.status != 0) - return; - - if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0) - return; - - if (rp.hci_version < HCI_SPEC_V12) { - unit->hci_flags &= ~BTF_INIT_COMMANDS; - wakeup(&unit->hci_init); - return; - } - - hci_send_cmd(unit, HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0); -} - -/* - * process results of read_local_commands command_complete event - */ -static void -hci_cmd_read_local_commands(struct hci_unit *unit, struct mbuf *m) -{ - hci_read_local_commands_rp rp; - - KASSERT(m->m_pkthdr.len >= sizeof(rp)); - m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); - m_adj(m, sizeof(rp)); - - if (rp.status != 0) - return; - - if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0) - return; - - unit->hci_flags &= ~BTF_INIT_COMMANDS; - memcpy(unit->hci_cmds, rp.commands, HCI_COMMANDS_SIZE); - - wakeup(&unit->hci_init); -} - -/* - * process results of reset command_complete event - * - * This has killed all the connections, so close down anything we have left, - * and reinitialise the unit. - */ -static void -hci_cmd_reset(struct hci_unit *unit, struct mbuf *m) -{ - hci_reset_rp rp; - struct hci_link *link, *next; - int acl; - - KASSERT(m->m_pkthdr.len >= sizeof(rp)); - m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); - m_adj(m, sizeof(rp)); - - if (rp.status != 0) - return; - - /* - * release SCO links first, since they may be holding - * an ACL link reference. - */ - for (acl = 0 ; acl < 2 ; acl++) { - next = TAILQ_FIRST(&unit->hci_links); - while ((link = next) != NULL) { - next = TAILQ_NEXT(link, hl_next); - if (acl || link->hl_type != HCI_LINK_ACL) - hci_link_free(link, ECONNABORTED); - } - } - - unit->hci_num_acl_pkts = 0; - unit->hci_num_sco_pkts = 0; - - if (hci_send_cmd(unit, HCI_CMD_READ_BDADDR, NULL, 0)) - return; - - if (hci_send_cmd(unit, HCI_CMD_READ_BUFFER_SIZE, NULL, 0)) - return; - - if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0)) - return; - - if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_VER, NULL, 0)) - return; -} - -/* - * process command_status event for create_con command - * - * a "Create Connection" command can sometimes fail to start for whatever - * reason and the command_status event returns failure but we get no - * indication of which connection failed (for instance in the case where - * we tried to open too many connections all at once) So, we keep a flag - * on the link to indicate pending status until the command_status event - * is returned to help us decide which needs to be failed. - * - * since created links are inserted at the tail of hci_links, we know that - * the first pending link we find will be the one that this command status - * refers to. - */ -static void -hci_cmd_create_con(struct hci_unit *unit, uint8_t status) -{ - struct hci_link *link; - - TAILQ_FOREACH(link, &unit->hci_links, hl_next) { - if ((link->hl_flags & HCI_LINK_CREATE_CON) == 0) - continue; - - link->hl_flags &= ~HCI_LINK_CREATE_CON; - - switch(status) { - case 0x00: /* success */ - break; - - case 0x0c: /* "Command Disallowed" */ - hci_link_free(link, EBUSY); - break; - - default: /* some other trouble */ - hci_link_free(link, /*EPROTO*/ECONNABORTED); - break; - } - - return; - } -} diff --git a/sys/netbt/hci_ioctl.c b/sys/netbt/hci_ioctl.c deleted file mode 100644 index 4ecba4faa40..00000000000 --- a/sys/netbt/hci_ioctl.c +++ /dev/null @@ -1,298 +0,0 @@ -/* $OpenBSD: hci_ioctl.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */ -/* $NetBSD: hci_ioctl.c,v 1.7 2007/11/28 20:16:12 plunky Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/domain.h> -#include <sys/ioctl.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> -#include <netbt/rfcomm.h> - -#ifdef BLUETOOTH_DEBUG -#define BDADDR(bd) (bd).b[5], (bd).b[4], (bd).b[3], \ - (bd).b[2], (bd).b[1], (bd).b[0] - -static void -hci_dump(void) -{ - struct hci_unit *unit; - struct hci_link *link; - struct l2cap_channel *chan; - struct rfcomm_session *rs; - struct rfcomm_dlc *dlc; - - printf("HCI:\n"); - TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { - printf("UNIT %s: flags 0x%4.4x, " - "num_cmd=%d, num_acl=%d, num_sco=%d\n", - device_xname(unit->hci_dev), unit->hci_flags, - unit->hci_num_cmd_pkts, - unit->hci_num_acl_pkts, - unit->hci_num_sco_pkts); - TAILQ_FOREACH(link, &unit->hci_links, hl_next) { - printf("+HANDLE #%d: %s " - "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "state %d, refcnt %d\n", - link->hl_handle, - (link->hl_type == HCI_LINK_ACL ? "ACL":"SCO"), - BDADDR(link->hl_bdaddr), - link->hl_state, link->hl_refcnt); - } - } - - printf("L2CAP:\n"); - LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) { - printf("CID #%d state %d, psm=0x%4.4x, " - "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", - chan->lc_lcid, chan->lc_state, chan->lc_raddr.bt_psm, - BDADDR(chan->lc_laddr.bt_bdaddr), - BDADDR(chan->lc_raddr.bt_bdaddr)); - } - - LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) { - printf("LISTEN psm=0x%4.4x, " - "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", - chan->lc_laddr.bt_psm, - BDADDR(chan->lc_laddr.bt_bdaddr)); - } - - printf("RFCOMM:\n"); - LIST_FOREACH(rs, &rfcomm_session_active, rs_next) { - chan = rs->rs_l2cap; - printf("SESSION: state=%d, flags=0x%4.4x, psm 0x%4.4x " - "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", - rs->rs_state, rs->rs_flags, chan->lc_raddr.bt_psm, - BDADDR(chan->lc_laddr.bt_bdaddr), - BDADDR(chan->lc_raddr.bt_bdaddr)); - LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) { - printf("+DLC channel=%d, dlci=%d, " - "state=%d, flags=0x%4.4x, rxcred=%d, rxsize=%ld, " - "txcred=%d, pending=%d, txqlen=%d\n", - dlc->rd_raddr.bt_channel, dlc->rd_dlci, - dlc->rd_state, dlc->rd_flags, - dlc->rd_rxcred, (unsigned long)dlc->rd_rxsize, - dlc->rd_txcred, dlc->rd_pending, - (dlc->rd_txbuf ? dlc->rd_txbuf->m_pkthdr.len : 0)); - } - } - - LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) { - chan = rs->rs_l2cap; - printf("LISTEN: psm 0x%4.4x, " - "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", - chan->lc_laddr.bt_psm, - BDADDR(chan->lc_laddr.bt_bdaddr)); - LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) - printf("+DLC channel=%d\n", dlc->rd_laddr.bt_channel); - } -} - -#undef BDADDR -#endif - -int -hci_ioctl(unsigned long cmd, void *data, struct proc *p) -{ - struct btreq *btr = data; - struct hci_unit *unit; - int err = 0; - - DPRINTFN(1, "cmd %#lx\n", cmd); - - switch(cmd) { -#ifdef BLUETOOTH_DEBUG - case SIOCBTDUMP: - hci_dump(); - return 0; -#endif - /* - * Get unit info based on address rather than name - */ - case SIOCGBTINFOA: - unit = hci_unit_lookup(&btr->btr_bdaddr); - if (unit == NULL) - return ENXIO; - - break; - - /* - * The remaining ioctl's all use the same btreq structure and - * index on the name of the device, so we look that up first. - */ - case SIOCNBTINFO: - /* empty name means give the first unit */ - if (btr->btr_name[0] == '\0') { - unit = NULL; - break; - } - - /* else fall through and look it up */ - case SIOCGBTINFO: - case SIOCSBTFLAGS: - case SIOCSBTPOLICY: - case SIOCSBTPTYPE: - case SIOCGBTSTATS: - case SIOCZBTSTATS: - case SIOCSBTSCOMTU: - TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { - if (strncmp(device_xname(unit->hci_dev), btr->btr_name, - HCI_DEVNAME_SIZE) == 0) - break; - } - - if (unit == NULL) - return ENXIO; - - break; - - default: /* not one of mine */ - return EPASSTHROUGH; - } - - switch(cmd) { - case SIOCNBTINFO: /* get next info */ - if (unit) - unit = TAILQ_NEXT(unit, hci_next); - else - unit = TAILQ_FIRST(&hci_unit_list); - - if (unit == NULL) { - err = ENXIO; - break; - } - - /* and fall through to */ - case SIOCGBTINFO: /* get unit info */ - case SIOCGBTINFOA: /* get info by address */ - memset(btr, 0, sizeof(struct btreq)); - strlcpy(btr->btr_name, device_xname(unit->hci_dev), HCI_DEVNAME_SIZE); - bdaddr_copy(&btr->btr_bdaddr, &unit->hci_bdaddr); - - btr->btr_flags = unit->hci_flags; - - btr->btr_num_cmd = unit->hci_num_cmd_pkts; - btr->btr_num_acl = unit->hci_num_acl_pkts; - btr->btr_num_sco = unit->hci_num_sco_pkts; - btr->btr_acl_mtu = unit->hci_max_acl_size; - btr->btr_sco_mtu = unit->hci_max_sco_size; - - btr->btr_packet_type = unit->hci_packet_type; - btr->btr_link_policy = unit->hci_link_policy; - break; - - case SIOCSBTFLAGS: /* set unit flags (privileged) */ - err = suser(p, 0); - if (err) - break; - - if ((unit->hci_flags & BTF_UP) - && (btr->btr_flags & BTF_UP) == 0) { - hci_disable(unit); - unit->hci_flags &= ~BTF_UP; - } - - unit->hci_flags |= (btr->btr_flags & BTF_INIT); - - if ((unit->hci_flags & BTF_UP) == 0 - && (btr->btr_flags & BTF_UP)) { - err = hci_enable(unit); - if (err) - break; - - unit->hci_flags |= BTF_UP; - } - - btr->btr_flags = unit->hci_flags; - break; - - case SIOCSBTPOLICY: /* set unit link policy (privileged) */ - err = suser(p, 0); - if (err) - break; - - unit->hci_link_policy = btr->btr_link_policy; - unit->hci_link_policy &= unit->hci_lmp_mask; - btr->btr_link_policy = unit->hci_link_policy; - break; - - case SIOCSBTPTYPE: /* set unit packet types (privileged) */ - err = suser(p, 0); - if (err) - break; - - unit->hci_packet_type = btr->btr_packet_type; - unit->hci_packet_type &= unit->hci_acl_mask; - btr->btr_packet_type = unit->hci_packet_type; - break; - - case SIOCGBTSTATS: /* get unit statistics */ - (*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 0); - break; - - case SIOCZBTSTATS: /* get & reset unit statistics */ - err = suser(p, 0); - if (err) - break; - - (*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 1); - break; - - case SIOCSBTSCOMTU: /* set sco_mtu value for unit */ - /* - * This is a temporary ioctl and may not be supported - * in the future. The need is that if SCO packets are - * sent to USB bluetooth controllers that are not an - * integer number of frame sizes, the USB bus locks up. - */ - err = suser(p, 0); - if (err) - break; - - unit->hci_max_sco_size = btr->btr_sco_mtu; - break; - - default: - err = EFAULT; - break; - } - - return err; -} diff --git a/sys/netbt/hci_link.c b/sys/netbt/hci_link.c deleted file mode 100644 index 6a9055413c5..00000000000 --- a/sys/netbt/hci_link.c +++ /dev/null @@ -1,1047 +0,0 @@ -/* $OpenBSD: hci_link.c,v 1.11 2010/07/29 14:40:47 blambert Exp $ */ -/* $NetBSD: hci_link.c,v 1.20 2008/04/24 11:38:37 ad Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/pool.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> -#include <netbt/sco.h> - -/******************************************************************************* - * - * HCI ACL Connections - */ - -/* - * Automatically expire unused ACL connections after this number of - * seconds (if zero, do not expire unused connections) [sysctl] - */ -int hci_acl_expiry = 10; /* seconds */ - -/* - * hci_acl_open(unit, bdaddr) - * - * open ACL connection to remote bdaddr. Only one ACL connection is permitted - * between any two Bluetooth devices, so we look for an existing one before - * trying to start a new one. - */ -struct hci_link * -hci_acl_open(struct hci_unit *unit, bdaddr_t *bdaddr) -{ - struct hci_link *link; - struct hci_memo *memo; - hci_create_con_cp cp; - int err; - - KASSERT(unit != NULL); - KASSERT(bdaddr != NULL); - - link = hci_link_lookup_bdaddr(unit, bdaddr, HCI_LINK_ACL); - if (link == NULL) { - link = hci_link_alloc(unit, bdaddr, HCI_LINK_ACL); - if (link == NULL) - return NULL; - } - - switch(link->hl_state) { - case HCI_LINK_CLOSED: - /* - * open connection to remote device - */ - memset(&cp, 0, sizeof(cp)); - bdaddr_copy(&cp.bdaddr, bdaddr); - cp.pkt_type = htole16(unit->hci_packet_type); - - memo = hci_memo_find(unit, bdaddr); - if (memo != NULL) { - cp.page_scan_rep_mode = memo->page_scan_rep_mode; - cp.page_scan_mode = memo->page_scan_mode; - cp.clock_offset = memo->clock_offset; - } - - if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH) - cp.accept_role_switch = 1; - - err = hci_send_cmd(unit, HCI_CMD_CREATE_CON, &cp, sizeof(cp)); - if (err) { - hci_link_free(link, err); - return NULL; - } - - link->hl_flags |= HCI_LINK_CREATE_CON; - link->hl_state = HCI_LINK_WAIT_CONNECT; - break; - - case HCI_LINK_WAIT_CONNECT: - case HCI_LINK_WAIT_AUTH: - case HCI_LINK_WAIT_ENCRYPT: - case HCI_LINK_WAIT_SECURE: - /* - * somebody else already trying to connect, we just - * sit on the bench with them.. - */ - break; - - case HCI_LINK_OPEN: - /* - * If already open, halt any expiry timeouts. We dont need - * to care about already invoking timeouts since refcnt >0 - * will keep the link alive. - */ - timeout_del(&link->hl_expire); - break; - - default: - UNKNOWN(link->hl_state); - return NULL; - } - - /* open */ - link->hl_refcnt++; - - return link; -} - -/* - * Close ACL connection. When there are no more references to this link, - * we can either close it down or schedule a delayed closedown. - */ -void -hci_acl_close(struct hci_link *link, int err) -{ - - KASSERT(link != NULL); - - if (--link->hl_refcnt == 0) { - if (link->hl_state == HCI_LINK_CLOSED) - hci_link_free(link, err); - else if (hci_acl_expiry > 0) - timeout_add_sec(&link->hl_expire, hci_acl_expiry); - } -} - -/* - * Incoming ACL connection. - * - * For now, we accept all connections but it would be better to check - * the L2CAP listen list and only accept when there is a listener - * available. - * - * There should not be a link to the same bdaddr already, we check - * anyway though its left unhandled for now. - */ -struct hci_link * -hci_acl_newconn(struct hci_unit *unit, bdaddr_t *bdaddr) -{ - struct hci_link *link; - - link = hci_link_lookup_bdaddr(unit, bdaddr, HCI_LINK_ACL); - if (link != NULL) - return NULL; - - link = hci_link_alloc(unit, bdaddr, HCI_LINK_ACL); - if (link != NULL) { - link->hl_state = HCI_LINK_WAIT_CONNECT; - - if (hci_acl_expiry > 0) - timeout_add_sec(&link->hl_expire, hci_acl_expiry); - } - - return link; -} - -void -hci_acl_timeout(void *arg) -{ - struct hci_link *link = arg; - hci_discon_cp cp; - int err; - - mutex_enter(&bt_lock); - - if (link->hl_refcnt > 0) - goto out; - - DPRINTF("link #%d expired\n", link->hl_handle); - - switch (link->hl_state) { - case HCI_LINK_CLOSED: - case HCI_LINK_WAIT_CONNECT: - hci_link_free(link, ECONNRESET); - break; - - case HCI_LINK_WAIT_AUTH: - case HCI_LINK_WAIT_ENCRYPT: - case HCI_LINK_WAIT_SECURE: - case HCI_LINK_OPEN: - cp.con_handle = htole16(link->hl_handle); - cp.reason = 0x13; /* "Remote User Terminated Connection" */ - - err = hci_send_cmd(link->hl_unit, HCI_CMD_DISCONNECT, - &cp, sizeof(cp)); - - if (err) { - DPRINTF("error %d sending HCI_CMD_DISCONNECT\n", - err); - } - - break; - - default: - UNKNOWN(link->hl_state); - break; - } - -out: - mutex_exit(&bt_lock); -} - -/* - * Initiate any Link Mode change requests. - */ -int -hci_acl_setmode(struct hci_link *link) -{ - int err; - - KASSERT(link != NULL); - KASSERT(link->hl_unit != NULL); - - if (link->hl_state != HCI_LINK_OPEN) - return EINPROGRESS; - - if ((link->hl_flags & HCI_LINK_AUTH_REQ) - && !(link->hl_flags & HCI_LINK_AUTH)) { - hci_auth_req_cp cp; - - DPRINTF("(%s) requesting auth for handle #%d\n", - device_xname(link->hl_unit->hci_dev), link->hl_handle); - - link->hl_state = HCI_LINK_WAIT_AUTH; - cp.con_handle = htole16(link->hl_handle); - err = hci_send_cmd(link->hl_unit, HCI_CMD_AUTH_REQ, - &cp, sizeof(cp)); - - return (err == 0 ? EINPROGRESS : err); - } - - if ((link->hl_flags & HCI_LINK_ENCRYPT_REQ) - && !(link->hl_flags & HCI_LINK_ENCRYPT)) { - hci_set_con_encryption_cp cp; - - /* XXX we should check features for encryption capability */ - - DPRINTF("(%s) requesting encryption for handle #%d\n", - device_xname(link->hl_unit->hci_dev), link->hl_handle); - - link->hl_state = HCI_LINK_WAIT_ENCRYPT; - cp.con_handle = htole16(link->hl_handle); - cp.encryption_enable = 0x01; - - err = hci_send_cmd(link->hl_unit, HCI_CMD_SET_CON_ENCRYPTION, - &cp, sizeof(cp)); - - return (err == 0 ? EINPROGRESS : err); - } - - if ((link->hl_flags & HCI_LINK_SECURE_REQ)) { - hci_change_con_link_key_cp cp; - - /* always change link key for SECURE requests */ - link->hl_flags &= ~HCI_LINK_SECURE; - - DPRINTF("(%s) changing link key for handle #%d\n", - device_xname(link->hl_unit->hci_dev), link->hl_handle); - - link->hl_state = HCI_LINK_WAIT_SECURE; - cp.con_handle = htole16(link->hl_handle); - - err = hci_send_cmd(link->hl_unit, HCI_CMD_CHANGE_CON_LINK_KEY, - &cp, sizeof(cp)); - - return (err == 0 ? EINPROGRESS : err); - } - - return 0; -} - -/* - * Link Mode changed. - * - * This is called from event handlers when the mode change - * is complete. We notify upstream and restart the link. - */ -void -hci_acl_linkmode(struct hci_link *link) -{ - struct l2cap_channel *chan, *next; - int err, mode = 0; - - DPRINTF("(%s) handle #%d, auth %s, encrypt %s, secure %s\n", - device_xname(link->hl_unit->hci_dev), link->hl_handle, - (link->hl_flags & HCI_LINK_AUTH ? "on" : "off"), - (link->hl_flags & HCI_LINK_ENCRYPT ? "on" : "off"), - (link->hl_flags & HCI_LINK_SECURE ? "on" : "off")); - - if (link->hl_flags & HCI_LINK_AUTH) - mode |= L2CAP_LM_AUTH; - - if (link->hl_flags & HCI_LINK_ENCRYPT) - mode |= L2CAP_LM_ENCRYPT; - - if (link->hl_flags & HCI_LINK_SECURE) - mode |= L2CAP_LM_SECURE; - - /* - * The link state will only be OPEN here if the mode change - * was successful. So, we can proceed with L2CAP connections, - * or notify already establshed channels, to allow any that - * are dissatisfied to disconnect before we restart. - */ - next = LIST_FIRST(&l2cap_active_list); - while ((chan = next) != NULL) { - next = LIST_NEXT(chan, lc_ncid); - - if (chan->lc_link != link) - continue; - - switch(chan->lc_state) { - case L2CAP_WAIT_SEND_CONNECT_REQ: /* we are connecting */ - if ((mode & chan->lc_mode) != chan->lc_mode) { - l2cap_close(chan, ECONNABORTED); - break; - } - - chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP; - err = l2cap_send_connect_req(chan); - if (err) { - l2cap_close(chan, err); - break; - } - break; - - case L2CAP_WAIT_SEND_CONNECT_RSP: /* they are connecting */ - if ((mode & chan->lc_mode) != chan->lc_mode) { - l2cap_send_connect_rsp(link, chan->lc_ident, - 0, chan->lc_rcid, - L2CAP_SECURITY_BLOCK); - - l2cap_close(chan, ECONNABORTED); - break; - } - - l2cap_send_connect_rsp(link, chan->lc_ident, - chan->lc_lcid, chan->lc_rcid, - L2CAP_SUCCESS); - - chan->lc_state = L2CAP_WAIT_CONFIG; - chan->lc_flags |= (L2CAP_WAIT_CONFIG_RSP | L2CAP_WAIT_CONFIG_REQ); - err = l2cap_send_config_req(chan); - if (err) { - l2cap_close(chan, err); - break; - } - break; - - case L2CAP_WAIT_RECV_CONNECT_RSP: - case L2CAP_WAIT_CONFIG: - case L2CAP_OPEN: /* already established */ - (*chan->lc_proto->linkmode)(chan->lc_upper, mode); - break; - - default: - break; - } - } - - link->hl_state = HCI_LINK_OPEN; - hci_acl_start(link); -} - -/* - * Receive ACL Data - * - * we accumulate packet fragments on the hci_link structure - * until a full L2CAP frame is ready, then send it on. - */ -void -hci_acl_recv(struct mbuf *m, struct hci_unit *unit) -{ - struct hci_link *link; - hci_acldata_hdr_t hdr; - uint16_t handle, want; - int pb, got; - - KASSERT(m != NULL); - KASSERT(unit != NULL); - - KASSERT(m->m_pkthdr.len >= sizeof(hdr)); - m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); - m_adj(m, sizeof(hdr)); - -#ifdef DIAGNOSTIC - if (hdr.type != HCI_ACL_DATA_PKT) { - printf("%s: bad ACL packet type\n", - device_xname(unit->hci_dev)); - goto bad; - } - - if (m->m_pkthdr.len != letoh16(hdr.length)) { - printf("%s: bad ACL packet length (%d != %d)\n", - device_xname(unit->hci_dev), m->m_pkthdr.len, - letoh16(hdr.length)); - goto bad; - } -#endif - - hdr.length = letoh16(hdr.length); - hdr.con_handle = letoh16(hdr.con_handle); - handle = HCI_CON_HANDLE(hdr.con_handle); - pb = HCI_PB_FLAG(hdr.con_handle); - - link = hci_link_lookup_handle(unit, handle); - if (link == NULL) { - hci_discon_cp cp; - - DPRINTF("%s: dumping packet for unknown handle #%d\n", - device_xname(unit->hci_dev), handle); - - /* - * There is no way to find out what this connection handle is - * for, just get rid of it. This may happen, if a USB dongle - * is plugged into a self powered hub and does not reset when - * the system is shut down. - */ - cp.con_handle = htole16(handle); - cp.reason = 0x13; /* "Remote User Terminated Connection" */ - hci_send_cmd(unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp)); - goto bad; - } - - switch (pb) { - case HCI_PACKET_START: - if (link->hl_rxp != NULL) - printf("%s: dropped incomplete ACL packet\n", - device_xname(unit->hci_dev)); - - if (m->m_pkthdr.len < sizeof(l2cap_hdr_t)) { - printf("%s: short ACL packet\n", - device_xname(unit->hci_dev)); - - goto bad; - } - - link->hl_rxp = m; - got = m->m_pkthdr.len; - break; - - case HCI_PACKET_FRAGMENT: - if (link->hl_rxp == NULL) { - printf("%s: unexpected packet fragment\n", - device_xname(unit->hci_dev)); - - goto bad; - } - - got = m->m_pkthdr.len + link->hl_rxp->m_pkthdr.len; - m_cat(link->hl_rxp, m); - m = link->hl_rxp; - m->m_pkthdr.len = got; - break; - - default: - printf("%s: unknown packet type\n", - device_xname(unit->hci_dev)); - - goto bad; - } - - m_copydata(m, 0, sizeof(want), (caddr_t)&want); - want = letoh16(want) + sizeof(l2cap_hdr_t) - got; - - if (want > 0) - return; - - link->hl_rxp = NULL; - - if (want == 0) { - l2cap_recv_frame(m, link); - return; - } - -bad: - m_freem(m); -} - -/* - * Send ACL data on link - * - * We must fragment packets into chunks of less than unit->hci_max_acl_size and - * prepend a relevant ACL header to each fragment. We keep a PDU structure - * attached to the link, so that completed fragments can be marked off and - * more data requested from above once the PDU is sent. - */ -int -hci_acl_send(struct mbuf *m, struct hci_link *link, - struct l2cap_channel *chan) -{ - struct l2cap_pdu *pdu; - struct mbuf *n = NULL; - int plen, mlen, num = 0; - - KASSERT(link != NULL); - KASSERT(m != NULL); - KASSERT(m->m_flags & M_PKTHDR); - KASSERT(m->m_pkthdr.len > 0); - - if (link->hl_state == HCI_LINK_CLOSED) { - m_freem(m); - return ENETDOWN; - } - - pdu = pool_get(&l2cap_pdu_pool, PR_NOWAIT); - if (pdu == NULL) - goto nomem; - - bzero(pdu, sizeof *pdu); - pdu->lp_chan = chan; - pdu->lp_pending = 0; - - plen = m->m_pkthdr.len; - mlen = link->hl_unit->hci_max_acl_size; - - DPRINTFN(5, "%s: handle #%d, plen = %d, max = %d\n", - device_xname(link->hl_unit->hci_dev), link->hl_handle, plen, mlen); - - while (plen > 0) { - if (plen > mlen) { - n = m_split(m, mlen, M_DONTWAIT); - if (n == NULL) - goto nomem; - } else { - mlen = plen; - } - - if (num++ == 0) - m->m_flags |= M_PROTO1; /* tag first fragment */ - - DPRINTFN(10, "(%s) chunk of %d (plen = %d) bytes\n", - device_xname(link->hl_unit->hci_dev), mlen, plen); - IF_ENQUEUE(&pdu->lp_data, m); - m = n; - plen -= mlen; - } - - TAILQ_INSERT_TAIL(&link->hl_txq, pdu, lp_next); - link->hl_txqlen += num; - - hci_acl_start(link); - - return 0; - -nomem: - if (m) m_freem(m); - if (pdu) { - IF_PURGE(&pdu->lp_data); - pool_put(&l2cap_pdu_pool, pdu); - } - - return ENOMEM; -} - -/* - * Start sending ACL data on link. - * - * This is called when the queue may need restarting: as new data - * is queued, after link mode changes have completed, or when device - * buffers have cleared. - * - * We may use all the available packet slots. The reason that we add - * the ACL encapsulation here rather than in hci_acl_send() is that L2CAP - * signal packets may be queued before the handle is given to us.. - */ -void -hci_acl_start(struct hci_link *link) -{ - struct hci_unit *unit; - hci_acldata_hdr_t *hdr; - struct l2cap_pdu *pdu; - struct mbuf *m; - uint16_t handle; - - KASSERT(link != NULL); - - unit = link->hl_unit; - KASSERT(unit != NULL); - - /* this is mainly to block ourselves (below) */ - if (link->hl_state != HCI_LINK_OPEN) - return; - - if (link->hl_txqlen == 0 || unit->hci_num_acl_pkts == 0) - return; - - /* find first PDU with data to send */ - pdu = TAILQ_FIRST(&link->hl_txq); - for (;;) { - if (pdu == NULL) - return; - - if (!IF_IS_EMPTY(&pdu->lp_data)) - break; - - pdu = TAILQ_NEXT(pdu, lp_next); - } - - while (unit->hci_num_acl_pkts > 0) { - IF_DEQUEUE(&pdu->lp_data, m); - KASSERT(m != NULL); - - if (m->m_flags & M_PROTO1) - handle = HCI_MK_CON_HANDLE(link->hl_handle, - HCI_PACKET_START, 0); - else - handle = HCI_MK_CON_HANDLE(link->hl_handle, - HCI_PACKET_FRAGMENT, 0); - - M_PREPEND(m, sizeof(*hdr), M_DONTWAIT); - if (m == NULL) - break; - - hdr = mtod(m, hci_acldata_hdr_t *); - hdr->type = HCI_ACL_DATA_PKT; - hdr->con_handle = htole16(handle); - hdr->length = htole16(m->m_pkthdr.len - sizeof(*hdr)); - - link->hl_txqlen--; - pdu->lp_pending++; - - hci_output_acl(unit, m); - - if (IF_IS_EMPTY(&pdu->lp_data)) { - if (pdu->lp_chan) { - /* - * This should enable streaming of PDUs - when - * we have placed all the fragments on the acl - * output queue, we trigger the L2CAP layer to - * send us down one more. Use a false state so - * we dont run into ourselves coming back from - * the future.. - */ - link->hl_state = HCI_LINK_BLOCK; - l2cap_start(pdu->lp_chan); - link->hl_state = HCI_LINK_OPEN; - } - - pdu = TAILQ_NEXT(pdu, lp_next); - if (pdu == NULL) - break; - } - } - - /* - * We had our turn now, move to the back of the queue to let - * other links have a go at the output buffers.. - */ - if (TAILQ_NEXT(link, hl_next)) { - TAILQ_REMOVE(&unit->hci_links, link, hl_next); - TAILQ_INSERT_TAIL(&unit->hci_links, link, hl_next); - } -} - -/* - * Confirm ACL packets cleared from Controller buffers. We scan our PDU - * list to clear pending fragments and signal upstream for more data - * when a PDU is complete. - */ -void -hci_acl_complete(struct hci_link *link, int num) -{ - struct l2cap_pdu *pdu; - struct l2cap_channel *chan; - - DPRINTFN(5, "(%s) handle #%d (%d)\n", - device_xname(link->hl_unit->hci_dev), link->hl_handle, num); - - while (num > 0) { - pdu = TAILQ_FIRST(&link->hl_txq); - if (pdu == NULL) { - printf("%s: %d packets completed on handle #%x " - "but none pending!\n", - device_xname(link->hl_unit->hci_dev), num, - link->hl_handle); - return; - } - - if (num >= pdu->lp_pending) { - num -= pdu->lp_pending; - pdu->lp_pending = 0; - - if (IF_IS_EMPTY(&pdu->lp_data)) { - TAILQ_REMOVE(&link->hl_txq, pdu, lp_next); - chan = pdu->lp_chan; - if (chan != NULL) { - chan->lc_pending--; - (*chan->lc_proto->complete) - (chan->lc_upper, 1); - - if (chan->lc_pending == 0) - l2cap_start(chan); - } - - pool_put(&l2cap_pdu_pool, pdu); - } - } else { - pdu->lp_pending -= num; - num = 0; - } - } -} - -/******************************************************************************* - * - * HCI SCO Connections - */ - -/* - * Incoming SCO Connection. We check the list for anybody willing - * to take it. - */ -struct hci_link * -hci_sco_newconn(struct hci_unit *unit, bdaddr_t *bdaddr) -{ - struct sockaddr_bt laddr, raddr; - struct sco_pcb *pcb, *new; - struct hci_link *sco, *acl; - - memset(&laddr, 0, sizeof(laddr)); - laddr.bt_len = sizeof(laddr); - laddr.bt_family = AF_BLUETOOTH; - bdaddr_copy(&laddr.bt_bdaddr, &unit->hci_bdaddr); - - memset(&raddr, 0, sizeof(raddr)); - raddr.bt_len = sizeof(raddr); - raddr.bt_family = AF_BLUETOOTH; - bdaddr_copy(&raddr.bt_bdaddr, bdaddr); - - /* - * There should already be an ACL link up and running before - * the controller sends us SCO connection requests, but you - * never know.. - */ - acl = hci_link_lookup_bdaddr(unit, bdaddr, HCI_LINK_ACL); - if (acl == NULL || acl->hl_state != HCI_LINK_OPEN) - return NULL; - - LIST_FOREACH(pcb, &sco_pcb, sp_next) { - if ((pcb->sp_flags & SP_LISTENING) == 0) - continue; - - new = (*pcb->sp_proto->newconn)(pcb->sp_upper, &laddr, &raddr); - if (new == NULL) - continue; - - /* - * Ok, got new pcb so we can start a new link and fill - * in all the details. - */ - bdaddr_copy(&new->sp_laddr, &unit->hci_bdaddr); - bdaddr_copy(&new->sp_raddr, bdaddr); - - sco = hci_link_alloc(unit, bdaddr, HCI_LINK_SCO); - if (sco == NULL) { - sco_detach(&new); - return NULL; - } - - sco->hl_link = hci_acl_open(unit, bdaddr); - KASSERT(sco->hl_link == acl); - - sco->hl_sco = new; - new->sp_link = sco; - - new->sp_mtu = unit->hci_max_sco_size; - return sco; - } - - return NULL; -} - -/* - * receive SCO packet, we only need to strip the header and send - * it to the right handler - */ -void -hci_sco_recv(struct mbuf *m, struct hci_unit *unit) -{ - struct hci_link *link; - hci_scodata_hdr_t hdr; - uint16_t handle; - - KASSERT(m != NULL); - KASSERT(unit != NULL); - - KASSERT(m->m_pkthdr.len >= sizeof(hdr)); - m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); - m_adj(m, sizeof(hdr)); - -#ifdef DIAGNOSTIC - if (hdr.type != HCI_SCO_DATA_PKT) { - printf("%s: bad SCO packet type\n", - device_xname(unit->hci_dev)); - goto bad; - } - - if (m->m_pkthdr.len != hdr.length) { - printf("%s: bad SCO packet length (%d != %d)\n", - device_xname(unit->hci_dev), m->m_pkthdr.len, hdr.length); - goto bad; - } -#endif - - hdr.con_handle = letoh16(hdr.con_handle); - handle = HCI_CON_HANDLE(hdr.con_handle); - - link = hci_link_lookup_handle(unit, handle); - if (link == NULL || link->hl_type == HCI_LINK_ACL) { - DPRINTF("%s: dumping packet for unknown handle #%d\n", - device_xname(unit->hci_dev), handle); - - goto bad; - } - - (*link->hl_sco->sp_proto->input)(link->hl_sco->sp_upper, m); - return; - -bad: - m_freem(m); -} - -void -hci_sco_start(struct hci_link *link) -{ -} - -/* - * SCO packets have completed at the controller, so we can - * signal up to free the buffer space. - */ -void -hci_sco_complete(struct hci_link *link, int num) -{ - - DPRINTFN(5, "handle #%d (num=%d)\n", link->hl_handle, num); - link->hl_sco->sp_pending--; - (*link->hl_sco->sp_proto->complete)(link->hl_sco->sp_upper, num); -} - -/******************************************************************************* - * - * Generic HCI Connection alloc/free/lookup etc - */ - -struct hci_link * -hci_link_alloc(struct hci_unit *unit, bdaddr_t *bdaddr, uint8_t type) -{ - struct hci_link *link; - - KASSERT(unit != NULL); - - link = malloc(sizeof *link, M_BLUETOOTH, M_NOWAIT | M_ZERO); - if (link == NULL) - return NULL; - - link->hl_unit = unit; - link->hl_type = type; - link->hl_state = HCI_LINK_CLOSED; - bdaddr_copy(&link->hl_bdaddr, bdaddr); - - /* init ACL portion */ - timeout_set(&link->hl_expire, hci_acl_timeout, link); - - TAILQ_INIT(&link->hl_txq); /* outgoing packets */ - TAILQ_INIT(&link->hl_reqs); /* request queue */ - - link->hl_mtu = L2CAP_MTU_DEFAULT; /* L2CAP signal mtu */ - link->hl_flush = L2CAP_FLUSH_TIMO_DEFAULT; /* flush timeout */ - - /* init SCO portion */ - /* &link->hl_data is already zero-initialized. */ - - /* attach to unit */ - TAILQ_INSERT_TAIL(&unit->hci_links, link, hl_next); - return link; -} - -void -hci_link_free(struct hci_link *link, int err) -{ - struct l2cap_req *req; - struct l2cap_pdu *pdu; - struct l2cap_channel *chan, *next; - - KASSERT(link != NULL); - - DPRINTF("(%s) #%d, type = %d, state = %d, refcnt = %d\n", - device_xname(link->hl_unit->hci_dev), link->hl_handle, - link->hl_type, link->hl_state, link->hl_refcnt); - - /* ACL reference count */ - if (link->hl_refcnt > 0) { - next = LIST_FIRST(&l2cap_active_list); - while ((chan = next) != NULL) { - next = LIST_NEXT(chan, lc_ncid); - if (chan->lc_link == link) - l2cap_close(chan, err); - } - } - KASSERT(link->hl_refcnt == 0); - - /* ACL L2CAP requests.. */ - while ((req = TAILQ_FIRST(&link->hl_reqs)) != NULL) - l2cap_request_free(req); - - KASSERT(TAILQ_EMPTY(&link->hl_reqs)); - - /* ACL outgoing data queue */ - while ((pdu = TAILQ_FIRST(&link->hl_txq)) != NULL) { - TAILQ_REMOVE(&link->hl_txq, pdu, lp_next); - IF_PURGE(&pdu->lp_data); - if (pdu->lp_pending) - link->hl_unit->hci_num_acl_pkts += pdu->lp_pending; - - pool_put(&l2cap_pdu_pool, pdu); - } - - KASSERT(TAILQ_EMPTY(&link->hl_txq)); - - /* ACL incoming data packet */ - if (link->hl_rxp != NULL) { - m_freem(link->hl_rxp); - link->hl_rxp = NULL; - } - - /* SCO master ACL link */ - if (link->hl_link != NULL) { - hci_acl_close(link->hl_link, err); - link->hl_link = NULL; - } - - /* SCO pcb */ - if (link->hl_sco != NULL) { - struct sco_pcb *pcb; - - pcb = link->hl_sco; - pcb->sp_link = NULL; - link->hl_sco = NULL; - (*pcb->sp_proto->disconnected)(pcb->sp_upper, err); - } - - /* flush any SCO data */ - IF_PURGE(&link->hl_data); - - /* - * Halt the timeout - if its already running we cannot free the - * link structure but the timeout function will call us back in - * any case. - */ - link->hl_state = HCI_LINK_CLOSED; - timeout_del(&link->hl_expire); - if (timeout_triggered(&link->hl_expire)) - return; - - /* - * If we made a note of clock offset, keep it in a memo - * to facilitate reconnections to this device - */ - if (link->hl_clock != 0) { - struct hci_memo *memo; - - memo = hci_memo_new(link->hl_unit, &link->hl_bdaddr); - if (memo != NULL) - memo->clock_offset = link->hl_clock; - } - - TAILQ_REMOVE(&link->hl_unit->hci_links, link, hl_next); - free(link, M_BLUETOOTH); -} - -/* - * Lookup HCI link by address and type. Note that for SCO links there may - * be more than one link per address, so we only return links with no - * handle (ie new links) - */ -struct hci_link * -hci_link_lookup_bdaddr(struct hci_unit *unit, bdaddr_t *bdaddr, uint8_t type) -{ - struct hci_link *link; - - KASSERT(unit != NULL); - KASSERT(bdaddr != NULL); - - TAILQ_FOREACH(link, &unit->hci_links, hl_next) { - if (link->hl_type != type) - continue; - - if (type == HCI_LINK_SCO && link->hl_handle != 0) - continue; - - if (bdaddr_same(&link->hl_bdaddr, bdaddr)) - break; - } - - return link; -} - -struct hci_link * -hci_link_lookup_handle(struct hci_unit *unit, uint16_t handle) -{ - struct hci_link *link; - - KASSERT(unit != NULL); - - TAILQ_FOREACH(link, &unit->hci_links, hl_next) { - if (handle == link->hl_handle) - break; - } - - return link; -} diff --git a/sys/netbt/hci_misc.c b/sys/netbt/hci_misc.c deleted file mode 100644 index 5cb144036a5..00000000000 --- a/sys/netbt/hci_misc.c +++ /dev/null @@ -1,181 +0,0 @@ -/* $OpenBSD: hci_misc.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */ -/* $NetBSD: hci_misc.c,v 1.3 2007/09/16 19:59:30 plunky Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> - -/* - * cache Inquiry Responses for this number of seconds for routing - * purposes [sysctl] - */ -int hci_memo_expiry = 600; - -/* - * set 'src' address for routing to 'dest' - */ -int -hci_route_lookup(bdaddr_t *src, bdaddr_t *dest) -{ - struct hci_unit *unit; - struct hci_link *link; - struct hci_memo *memo; - - /* - * Walk the ACL connections, if we have a connection - * to 'dest' already then thats best.. - */ - TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { - if ((unit->hci_flags & BTF_UP) == 0) - continue; - - TAILQ_FOREACH(link, &unit->hci_links, hl_next) { - if (link->hl_type != HCI_LINK_ACL) - continue; - - if (bdaddr_same(&link->hl_bdaddr, dest)) - goto found; - } - } - - /* - * Now check all the memos to see if there has been an - * inquiry repsonse.. - */ - TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { - if ((unit->hci_flags & BTF_UP) == 0) - continue; - - memo = hci_memo_find(unit, dest); - if (memo) - goto found; - } - - /* - * Last ditch effort, lets use the first unit we find - * thats up and running. (XXX settable default route?) - */ - TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { - if ((unit->hci_flags & BTF_UP) == 0) - continue; - - goto found; - } - - return EHOSTUNREACH; - -found: - bdaddr_copy(src, &unit->hci_bdaddr); - return 0; -} - -/* - * find unit memo from bdaddr - */ -struct hci_memo * -hci_memo_find(struct hci_unit *unit, bdaddr_t *bdaddr) -{ - struct hci_memo *memo, *m0; - struct timeval now; - - microtime(&now); - - m0 = LIST_FIRST(&unit->hci_memos); - while ((memo = m0) != NULL) { - m0 = LIST_NEXT(memo, next); - - if (now.tv_sec > memo->time.tv_sec + hci_memo_expiry) { - DPRINTF("memo %p too old (expiring)\n", memo); - hci_memo_free(memo); - continue; - } - - if (bdaddr_same(bdaddr, &memo->bdaddr)) { - DPRINTF("memo %p found\n", memo); - return memo; - } - } - - DPRINTF("no memo found\n"); - return NULL; -} - -/* - * Make a new memo on unit for bdaddr. If a memo exists, just - * update the timestamp. - */ -struct hci_memo * -hci_memo_new(struct hci_unit *unit, bdaddr_t *bdaddr) -{ - struct hci_memo *memo; - - memo = hci_memo_find(unit, bdaddr); - if (memo == NULL) { - memo = malloc(sizeof(struct hci_memo), - M_BLUETOOTH, M_NOWAIT | M_ZERO); - - if (memo == NULL) { - DPRINTFN(0, "no memory for memo!\n"); - return NULL; - } - - DPRINTF("memo created for %02x:%02x:%02x:%02x:%02x:%02x\n", - bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], - bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]); - - bdaddr_copy(&memo->bdaddr, bdaddr); - LIST_INSERT_HEAD(&unit->hci_memos, memo, next); - } - else - DPRINTF("memo updated for %02x:%02x:%02x:%02x:%02x:%02x\n", - bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], - bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]); - - microtime(&memo->time); - return memo; -} - -void -hci_memo_free(struct hci_memo *memo) -{ - - LIST_REMOVE(memo, next); - free(memo, M_BLUETOOTH); -} diff --git a/sys/netbt/hci_socket.c b/sys/netbt/hci_socket.c deleted file mode 100644 index d9d161cd185..00000000000 --- a/sys/netbt/hci_socket.c +++ /dev/null @@ -1,946 +0,0 @@ -/* $OpenBSD: hci_socket.c,v 1.8 2009/11/21 13:05:32 guenther Exp $ */ -/* $NetBSD: hci_socket.c,v 1.17 2008/08/06 15:01:24 plunky Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* load symbolic names */ -#ifdef BLUETOOTH_DEBUG -#define PRUREQUESTS -#define PRCOREQUESTS -#endif - -#include <sys/param.h> -#include <sys/domain.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> - -/******************************************************************************* - * - * HCI SOCK_RAW Sockets - for control of Bluetooth Devices - * - */ - -/* - * the raw HCI protocol control block - */ -struct hci_pcb { - struct socket *hp_socket; /* socket */ - unsigned int hp_flags; /* flags */ - bdaddr_t hp_laddr; /* local address */ - bdaddr_t hp_raddr; /* remote address */ - struct hci_filter hp_efilter; /* user event filter */ - struct hci_filter hp_pfilter; /* user packet filter */ - LIST_ENTRY(hci_pcb) hp_next; /* next HCI pcb */ -}; - -/* hp_flags */ -#define HCI_PRIVILEGED (1<<0) /* no security filter for root */ -#define HCI_DIRECTION (1<<1) /* direction control messages */ -#define HCI_PROMISCUOUS (1<<2) /* listen to all units */ - -LIST_HEAD(hci_pcb_list, hci_pcb) hci_pcb = LIST_HEAD_INITIALIZER(hci_pcb); - -/* sysctl defaults */ -int hci_sendspace = HCI_CMD_PKT_SIZE; -int hci_recvspace = 4096; - -/* supported commands opcode table */ -static const struct { - uint16_t opcode; - uint8_t offs; /* 0 - 63 */ - uint8_t mask; /* bit 0 - 7 */ - int16_t length; /* -1 if privileged */ -} hci_cmds[] = { - { HCI_CMD_INQUIRY, - 0, 0x01, sizeof(hci_inquiry_cp) }, - { HCI_CMD_INQUIRY_CANCEL, - 0, 0x02, -1 }, - { HCI_CMD_PERIODIC_INQUIRY, - 0, 0x04, -1 }, - { HCI_CMD_EXIT_PERIODIC_INQUIRY, - 0, 0x08, -1 }, - { HCI_CMD_CREATE_CON, - 0, 0x10, -1 }, - { HCI_CMD_DISCONNECT, - 0, 0x20, -1 }, - { HCI_CMD_ADD_SCO_CON, - 0, 0x40, -1 }, - { HCI_CMD_CREATE_CON_CANCEL, - 0, 0x80, -1 }, - { HCI_CMD_ACCEPT_CON, - 1, 0x01, -1 }, - { HCI_CMD_REJECT_CON, - 1, 0x02, -1 }, - { HCI_CMD_LINK_KEY_REP, - 1, 0x04, -1 }, - { HCI_CMD_LINK_KEY_NEG_REP, - 1, 0x08, -1 }, - { HCI_CMD_PIN_CODE_REP, - 1, 0x10, -1 }, - { HCI_CMD_PIN_CODE_NEG_REP, - 1, 0x20, -1 }, - { HCI_CMD_CHANGE_CON_PACKET_TYPE, - 1, 0x40, -1 }, - { HCI_CMD_AUTH_REQ, - 1, 0x80, -1 }, - { HCI_CMD_SET_CON_ENCRYPTION, - 2, 0x01, -1 }, - { HCI_CMD_CHANGE_CON_LINK_KEY, - 2, 0x02, -1 }, - { HCI_CMD_MASTER_LINK_KEY, - 2, 0x04, -1 }, - { HCI_CMD_REMOTE_NAME_REQ, - 2, 0x08, sizeof(hci_remote_name_req_cp) }, - { HCI_CMD_REMOTE_NAME_REQ_CANCEL, - 2, 0x10, -1 }, - { HCI_CMD_READ_REMOTE_FEATURES, - 2, 0x20, sizeof(hci_read_remote_features_cp) }, - { HCI_CMD_READ_REMOTE_EXTENDED_FEATURES, - 2, 0x40, sizeof(hci_read_remote_extended_features_cp) }, - { HCI_CMD_READ_REMOTE_VER_INFO, - 2, 0x80, sizeof(hci_read_remote_ver_info_cp) }, - { HCI_CMD_READ_CLOCK_OFFSET, - 3, 0x01, sizeof(hci_read_clock_offset_cp) }, - { HCI_CMD_READ_LMP_HANDLE, - 3, 0x02, sizeof(hci_read_lmp_handle_cp) }, - { HCI_CMD_HOLD_MODE, - 4, 0x02, -1 }, - { HCI_CMD_SNIFF_MODE, - 4, 0x04, -1 }, - { HCI_CMD_EXIT_SNIFF_MODE, - 4, 0x08, -1 }, - { HCI_CMD_PARK_MODE, - 4, 0x10, -1 }, - { HCI_CMD_EXIT_PARK_MODE, - 4, 0x20, -1 }, - { HCI_CMD_QOS_SETUP, - 4, 0x40, -1 }, - { HCI_CMD_ROLE_DISCOVERY, - 4, 0x80, sizeof(hci_role_discovery_cp) }, - { HCI_CMD_SWITCH_ROLE, - 5, 0x01, -1 }, - { HCI_CMD_READ_LINK_POLICY_SETTINGS, - 5, 0x02, sizeof(hci_read_link_policy_settings_cp) }, - { HCI_CMD_WRITE_LINK_POLICY_SETTINGS, - 5, 0x04, -1 }, - { HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS, - 5, 0x08, 0 }, - { HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS, - 5, 0x10, -1 }, - { HCI_CMD_FLOW_SPECIFICATION, - 5, 0x20, -1 }, - { HCI_CMD_SET_EVENT_MASK, - 5, 0x40, -1 }, - { HCI_CMD_RESET, - 5, 0x80, -1 }, - { HCI_CMD_SET_EVENT_FILTER, - 6, 0x01, -1 }, - { HCI_CMD_FLUSH, - 6, 0x02, -1 }, - { HCI_CMD_READ_PIN_TYPE, - 6, 0x04, 0 }, - { HCI_CMD_WRITE_PIN_TYPE, - 6, 0x08, -1 }, - { HCI_CMD_CREATE_NEW_UNIT_KEY, - 6, 0x10, -1 }, - { HCI_CMD_READ_STORED_LINK_KEY, - 6, 0x20, -1 }, - { HCI_CMD_WRITE_STORED_LINK_KEY, - 6, 0x40, -1 }, - { HCI_CMD_DELETE_STORED_LINK_KEY, - 6, 0x80, -1 }, - { HCI_CMD_WRITE_LOCAL_NAME, - 7, 0x01, -1 }, - { HCI_CMD_READ_LOCAL_NAME, - 7, 0x02, 0 }, - { HCI_CMD_READ_CON_ACCEPT_TIMEOUT, - 7, 0x04, 0 }, - { HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT, - 7, 0x08, -1 }, - { HCI_CMD_READ_PAGE_TIMEOUT, - 7, 0x10, 0 }, - { HCI_CMD_WRITE_PAGE_TIMEOUT, - 7, 0x20, -1 }, - { HCI_CMD_READ_SCAN_ENABLE, - 7, 0x40, 0 }, - { HCI_CMD_WRITE_SCAN_ENABLE, - 7, 0x80, -1 }, - { HCI_CMD_READ_PAGE_SCAN_ACTIVITY, - 8, 0x01, 0 }, - { HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY, - 8, 0x02, -1 }, - { HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY, - 8, 0x04, 0 }, - { HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY, - 8, 0x08, -1 }, - { HCI_CMD_READ_AUTH_ENABLE, - 8, 0x10, 0 }, - { HCI_CMD_WRITE_AUTH_ENABLE, - 8, 0x20, -1 }, - { HCI_CMD_READ_ENCRYPTION_MODE, - 8, 0x40, 0 }, - { HCI_CMD_WRITE_ENCRYPTION_MODE, - 8, 0x80, -1 }, - { HCI_CMD_READ_UNIT_CLASS, - 9, 0x01, 0 }, - { HCI_CMD_WRITE_UNIT_CLASS, - 9, 0x02, -1 }, - { HCI_CMD_READ_VOICE_SETTING, - 9, 0x04, 0 }, - { HCI_CMD_WRITE_VOICE_SETTING, - 9, 0x08, -1 }, - { HCI_CMD_READ_AUTO_FLUSH_TIMEOUT, - 9, 0x10, sizeof(hci_read_auto_flush_timeout_cp) }, - { HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT, - 9, 0x20, -1 }, - { HCI_CMD_READ_NUM_BROADCAST_RETRANS, - 9, 0x40, 0 }, - { HCI_CMD_WRITE_NUM_BROADCAST_RETRANS, - 9, 0x80, -1 }, - { HCI_CMD_READ_HOLD_MODE_ACTIVITY, - 10, 0x01, 0 }, - { HCI_CMD_WRITE_HOLD_MODE_ACTIVITY, - 10, 0x02, -1 }, - { HCI_CMD_READ_XMIT_LEVEL, - 10, 0x04, sizeof(hci_read_xmit_level_cp) }, - { HCI_CMD_READ_SCO_FLOW_CONTROL, - 10, 0x08, 0 }, - { HCI_CMD_WRITE_SCO_FLOW_CONTROL, - 10, 0x10, -1 }, - { HCI_CMD_HC2H_FLOW_CONTROL, - 10, 0x20, -1 }, - { HCI_CMD_HOST_BUFFER_SIZE, - 10, 0x40, -1 }, - { HCI_CMD_HOST_NUM_COMPL_PKTS, - 10, 0x80, -1 }, - { HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT, - 11, 0x01, sizeof(hci_read_link_supervision_timeout_cp) }, - { HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT, - 11, 0x02, -1 }, - { HCI_CMD_READ_NUM_SUPPORTED_IAC, - 11, 0x04, 0 }, - { HCI_CMD_READ_IAC_LAP, - 11, 0x08, 0 }, - { HCI_CMD_WRITE_IAC_LAP, - 11, 0x10, -1 }, - { HCI_CMD_READ_PAGE_SCAN_PERIOD, - 11, 0x20, 0 }, - { HCI_CMD_WRITE_PAGE_SCAN_PERIOD, - 11, 0x40, -1 }, - { HCI_CMD_READ_PAGE_SCAN, - 11, 0x80, 0 }, - { HCI_CMD_WRITE_PAGE_SCAN, - 12, 0x01, -1 }, - { HCI_CMD_SET_AFH_CLASSIFICATION, - 12, 0x02, -1 }, - { HCI_CMD_READ_INQUIRY_SCAN_TYPE, - 12, 0x10, 0 }, - { HCI_CMD_WRITE_INQUIRY_SCAN_TYPE, - 12, 0x20, -1 }, - { HCI_CMD_READ_INQUIRY_MODE, - 12, 0x40, 0 }, - { HCI_CMD_WRITE_INQUIRY_MODE, - 12, 0x80, -1 }, - { HCI_CMD_READ_PAGE_SCAN_TYPE, - 13, 0x01, 0 }, - { HCI_CMD_WRITE_PAGE_SCAN_TYPE, - 13, 0x02, -1 }, - { HCI_CMD_READ_AFH_ASSESSMENT, - 13, 0x04, 0 }, - { HCI_CMD_WRITE_AFH_ASSESSMENT, - 13, 0x08, -1 }, - { HCI_CMD_READ_LOCAL_VER, - 14, 0x08, 0 }, - { HCI_CMD_READ_LOCAL_COMMANDS, - 14, 0x10, 0 }, - { HCI_CMD_READ_LOCAL_FEATURES, - 14, 0x20, 0 }, - { HCI_CMD_READ_LOCAL_EXTENDED_FEATURES, - 14, 0x40, sizeof(hci_read_local_extended_features_cp) }, - { HCI_CMD_READ_BUFFER_SIZE, - 14, 0x80, 0 }, - { HCI_CMD_READ_COUNTRY_CODE, - 15, 0x01, 0 }, - { HCI_CMD_READ_BDADDR, - 15, 0x02, 0 }, - { HCI_CMD_READ_FAILED_CONTACT_CNTR, - 15, 0x04, sizeof(hci_read_failed_contact_cntr_cp) }, - { HCI_CMD_RESET_FAILED_CONTACT_CNTR, - 15, 0x08, -1 }, - { HCI_CMD_READ_LINK_QUALITY, - 15, 0x10, sizeof(hci_read_link_quality_cp) }, - { HCI_CMD_READ_RSSI, - 15, 0x20, sizeof(hci_read_rssi_cp) }, - { HCI_CMD_READ_AFH_CHANNEL_MAP, - 15, 0x40, sizeof(hci_read_afh_channel_map_cp) }, - { HCI_CMD_READ_CLOCK, - 15, 0x80, sizeof(hci_read_clock_cp) }, - { HCI_CMD_READ_LOOPBACK_MODE, - 16, 0x01, 0 }, - { HCI_CMD_WRITE_LOOPBACK_MODE, - 16, 0x02, -1 }, - { HCI_CMD_ENABLE_UNIT_UNDER_TEST, - 16, 0x04, -1 }, - { HCI_CMD_SETUP_SCO_CON, - 16, 0x08, -1 }, - { HCI_CMD_ACCEPT_SCO_CON_REQ, - 16, 0x10, -1 }, - { HCI_CMD_REJECT_SCO_CON_REQ, - 16, 0x20, -1 }, - { HCI_CMD_READ_EXTENDED_INQUIRY_RSP, - 17, 0x01, 0 }, - { HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP, - 17, 0x02, -1 }, - { HCI_CMD_REFRESH_ENCRYPTION_KEY, - 17, 0x04, -1 }, - { HCI_CMD_SNIFF_SUBRATING, - 17, 0x10, -1 }, - { HCI_CMD_READ_SIMPLE_PAIRING_MODE, - 17, 0x20, 0 }, - { HCI_CMD_WRITE_SIMPLE_PAIRING_MODE, - 17, 0x40, -1 }, - { HCI_CMD_READ_LOCAL_OOB_DATA, - 17, 0x80, -1 }, - { HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER, - 18, 0x01, 0 }, - { HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER, - 18, 0x02, -1 }, - { HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING, - 18, 0x04, 0 }, - { HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING, - 18, 0x08, -1 }, - { HCI_CMD_IO_CAPABILITY_REP, - 18, 0x80, -1 }, - { HCI_CMD_USER_CONFIRM_REP, - 19, 0x01, -1 }, - { HCI_CMD_USER_CONFIRM_NEG_REP, - 19, 0x02, -1 }, - { HCI_CMD_USER_PASSKEY_REP, - 19, 0x04, -1 }, - { HCI_CMD_USER_PASSKEY_NEG_REP, - 19, 0x08, -1 }, - { HCI_CMD_OOB_DATA_REP, - 19, 0x10, -1 }, - { HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE, - 19, 0x20, -1 }, - { HCI_CMD_ENHANCED_FLUSH, - 19, 0x40, -1 }, - { HCI_CMD_OOB_DATA_NEG_REP, - 19, 0x80, -1 }, - { HCI_CMD_SEND_KEYPRESS_NOTIFICATION, - 20, 0x40, -1 }, - { HCI_CMD_IO_CAPABILITY_NEG_REP, - 20, 0x80, -1 }, -}; - -/* - * Security filter routines for unprivileged users. - * Allow all but a few critical events, and only permit read commands. - * If a unit is given, verify the command is supported. - */ - -static int -hci_security_check_opcode(struct hci_unit *unit, uint16_t opcode) -{ - int i; - - for (i = 0 ; i < sizeof(hci_cmds) / sizeof(hci_cmds[0]); i++) { - if (opcode != hci_cmds[i].opcode) - continue; - - if (unit == NULL - || (unit->hci_cmds[hci_cmds[i].offs] & hci_cmds[i].mask)) - return hci_cmds[i].length; - - break; - } - - return -1; -} - -static int -hci_security_check_event(uint8_t event) -{ - - switch (event) { - case HCI_EVENT_RETURN_LINK_KEYS: - case HCI_EVENT_LINK_KEY_NOTIFICATION: - case HCI_EVENT_USER_CONFIRM_REQ: - case HCI_EVENT_USER_PASSKEY_NOTIFICATION: - case HCI_EVENT_VENDOR: - return -1; /* disallowed */ - } - - return 0; /* ok */ -} - -/* - * When command packet reaches the device, we can drop - * it from the socket buffer (called from hci_output_acl) - */ -void -hci_drop(void *arg) -{ - struct socket *so = arg; - - sbdroprecord(&so->so_snd); - sowwakeup(so); -} - -/* - * HCI socket is going away and has some pending packets. We let them - * go by design, but remove the context pointer as it will be invalid - * and we no longer need to be notified. - */ -static void -hci_cmdwait_flush(struct socket *so) -{ - struct hci_unit *unit; - struct socket *ctx; - struct mbuf *m; - - DPRINTF("flushing %p\n", so); - - TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { - IF_POLL(&unit->hci_cmdwait, m); - while (m != NULL) { - ctx = M_GETCTX(m, struct socket *); - if (ctx == so) - M_SETCTX(m, NULL); - - m = m->m_nextpkt; - } - } -} - -/* - * HCI send packet - * This came from userland, so check it out. - */ -static int -hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) -{ - struct hci_unit *unit; - struct mbuf *m0; - hci_cmd_hdr_t hdr; - int err; - - KASSERT(m != NULL); - KASSERT(addr != NULL); - - /* wants at least a header to start with */ - if (m->m_pkthdr.len < sizeof(hdr)) { - err = EMSGSIZE; - goto bad; - } - m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); - hdr.opcode = letoh16(hdr.opcode); - - /* only allows CMD packets to be sent */ - if (hdr.type != HCI_CMD_PKT) { - err = EINVAL; - goto bad; - } - - /* validates packet length */ - if (m->m_pkthdr.len != sizeof(hdr) + hdr.length) { - err = EMSGSIZE; - goto bad; - } - - /* finds destination */ - unit = hci_unit_lookup(addr); - if (unit == NULL) { - err = ENETDOWN; - goto bad; - } - - /* security checks for unprivileged users */ - if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 - && hci_security_check_opcode(unit, hdr.opcode) != hdr.length) { - err = EPERM; - goto bad; - } - - /* makes a copy for precious to keep */ - m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if (m0 == NULL) { - err = ENOMEM; - goto bad; - } - sbappendrecord(&pcb->hp_socket->so_snd, m0); - M_SETCTX(m, pcb->hp_socket); /* enable drop callback */ - - DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", device_xname(unit->hci_dev), - HCI_OGF(hdr.opcode), HCI_OCF(hdr.opcode)); - - /* Sendss it */ - if (unit->hci_num_cmd_pkts == 0) - IF_ENQUEUE(&unit->hci_cmdwait, m); - else - hci_output_cmd(unit, m); - - return 0; - -bad: - DPRINTF("packet (%d bytes) not sent (error %d)\n", - m->m_pkthdr.len, err); - if (m) m_freem(m); - return err; -} - -/* - * User Request. - * up is socket - * m is either - * optional mbuf chain containing message - * ioctl command (PRU_CONTROL) - * nam is either - * optional mbuf chain containing an address - * ioctl data (PRU_CONTROL) - * optionally, protocol number (PRU_ATTACH) - * ctl is optional mbuf chain containing socket options - * l is pointer to process requesting action (if any) - * - * we are responsible for disposing of m and ctl if - * they are mbuf chains - */ -int -hci_usrreq(struct socket *up, int req, struct mbuf *m, - struct mbuf *nam, struct mbuf *ctl, struct proc *p) -{ - struct hci_pcb *pcb = (struct hci_pcb *)up->so_pcb; - struct sockaddr_bt *sa; - int err = 0; - -#ifdef notyet /* XXX */ - DPRINTFN(2, "%s\n", prurequests[req]); -#endif - - switch(req) { - case PRU_CONTROL: - mutex_enter(&bt_lock); - err = hci_ioctl((unsigned long)m, (void *)nam, curproc); - mutex_exit(&bt_lock); - return err; - - case PRU_ATTACH: - /* XXX solock() and bt_lock fiddling in NetBSD */ - if (pcb) - return EINVAL; - err = soreserve(up, hci_sendspace, hci_recvspace); - if (err) - return err; - - pcb = malloc(sizeof *pcb, M_PCB, M_NOWAIT | M_ZERO); - if (pcb == NULL) - return ENOMEM; - - up->so_pcb = pcb; - pcb->hp_socket = up; - - if (curproc == NULL || suser(curproc, 0) == 0) - pcb->hp_flags |= HCI_PRIVILEGED; - - /* - * Set default user filter. By default, socket only passes - * Command_Complete and Command_Status Events. - */ - hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter); - hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter); - hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter); - - LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next); - - return 0; - } - - /* anything after here *requires* a pcb */ - if (pcb == NULL) { - err = EINVAL; - goto release; - } - - switch(req) { - case PRU_DISCONNECT: - bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY); - - /* XXX we cannot call soisdisconnected() here, as it sets - * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being, - * that soisconnected() does not clear these and if you - * try to reconnect this socket (which is permitted) you - * get a broken pipe when you try to write any data. - */ - up->so_state &= ~SS_ISCONNECTED; - break; - - case PRU_ABORT: - soisdisconnected(up); - /* fall through to */ - case PRU_DETACH: - if (up->so_snd.sb_mb != NULL) - hci_cmdwait_flush(up); - - up->so_pcb = NULL; - LIST_REMOVE(pcb, hp_next); - free(pcb, M_PCB); - return 0; - - case PRU_BIND: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - - if (sa->bt_len != sizeof(struct sockaddr_bt)) - return EINVAL; - - if (sa->bt_family != AF_BLUETOOTH) - return EAFNOSUPPORT; - - bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr); - - if (bdaddr_any(&sa->bt_bdaddr)) - pcb->hp_flags |= HCI_PROMISCUOUS; - else - pcb->hp_flags &= ~HCI_PROMISCUOUS; - - return 0; - - case PRU_CONNECT: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - - if (sa->bt_len != sizeof(struct sockaddr_bt)) - return EINVAL; - - if (sa->bt_family != AF_BLUETOOTH) - return EAFNOSUPPORT; - - if (hci_unit_lookup(&sa->bt_bdaddr) == NULL) - return EADDRNOTAVAIL; - - bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr); - soisconnected(up); - return 0; - - case PRU_PEERADDR: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - - memset(sa, 0, sizeof(struct sockaddr_bt)); - nam->m_len = - sa->bt_len = sizeof(struct sockaddr_bt); - sa->bt_family = AF_BLUETOOTH; - bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr); - return 0; - - case PRU_SOCKADDR: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - - memset(sa, 0, sizeof(struct sockaddr_bt)); - nam->m_len = - sa->bt_len = sizeof(struct sockaddr_bt); - sa->bt_family = AF_BLUETOOTH; - bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr); - return 0; - - case PRU_SHUTDOWN: - socantsendmore(up); - break; - - case PRU_SEND: - sa = NULL; - if (nam) { - sa = mtod(nam, struct sockaddr_bt *); - - if (sa->bt_len != sizeof(struct sockaddr_bt)) { - err = EINVAL; - goto release; - } - - if (sa->bt_family != AF_BLUETOOTH) { - err = EAFNOSUPPORT; - goto release; - } - } - - if (ctl) /* have no use for this */ - m_freem(ctl); - - return hci_send(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr)); - - case PRU_SENSE: - return 0; /* (no sense - Doh!) */ - - case PRU_RCVD: - case PRU_RCVOOB: - return EOPNOTSUPP; /* (no release) */ - - case PRU_ACCEPT: - case PRU_CONNECT2: - case PRU_LISTEN: - case PRU_SENDOOB: - case PRU_FASTTIMO: - case PRU_SLOWTIMO: - case PRU_PROTORCV: - case PRU_PROTOSEND: - err = EOPNOTSUPP; - break; - - default: - UNKNOWN(req); - err = EOPNOTSUPP; - break; - } - -release: - if (m) - m_freem(m); - if (ctl) - m_freem(ctl); - return err; -} - -/* - * get/set socket options - */ -int -hci_ctloutput(int req, struct socket *so, int level, - int optname, struct mbuf **opt) -{ - struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb; - struct mbuf *m; - int err = 0; - -#ifdef notyet /* XXX */ - DPRINTFN(2, "req %s\n", prcorequests[req]); -#endif - - if (pcb == NULL) - return EINVAL; - - if (level != BTPROTO_HCI) { - err = EINVAL; - if (req == PRCO_SETOPT && *opt) - m_free(*opt); - } else switch(req) { - case PRCO_GETOPT: - m = m_get(M_WAIT, MT_SOOPTS); - switch (optname) { - case SO_HCI_EVT_FILTER: - m->m_len = sizeof(struct hci_filter); - memcpy(mtod(m, void *), &pcb->hp_efilter, m->m_len); - break; - - case SO_HCI_PKT_FILTER: - m->m_len = sizeof(struct hci_filter); - memcpy(mtod(m, void *), &pcb->hp_pfilter, m->m_len); - break; - - case SO_HCI_DIRECTION: - m->m_len = sizeof(int); - if (pcb->hp_flags & HCI_DIRECTION) - *mtod(m, int *) = 1; - else - *mtod(m, int *) = 0; - break; - - default: - err = ENOPROTOOPT; - m_freem(m); - m = NULL; - break; - } - *opt = m; - break; - - case PRCO_SETOPT: - m = *opt; - if (m) switch (optname) { - case SO_HCI_EVT_FILTER: /* set event filter */ - if (m == NULL || m->m_len > sizeof(struct hci_filter)) - err = EINVAL; - else { - memcpy(&pcb->hp_efilter, mtod(m, void *), - m->m_len); - memset((char *)&pcb->hp_efilter + m->m_len, - 0, sizeof(struct hci_filter) - m->m_len); - } - break; - - case SO_HCI_PKT_FILTER: /* set packet filter */ - if (m == NULL || m->m_len > sizeof(struct hci_filter)) - err = EINVAL; - else { - memcpy(&pcb->hp_pfilter, mtod(m, void *), - m->m_len); - memset((char *)&pcb->hp_pfilter + m->m_len, - 0, sizeof(struct hci_filter) - m->m_len); - } - break; - - case SO_HCI_DIRECTION: /* request direction ctl messages */ - if (m == NULL || m->m_len != sizeof(int)) - err = EINVAL; - else { - if (*mtod(m, int *)) - pcb->hp_flags |= HCI_DIRECTION; - else - pcb->hp_flags &= ~HCI_DIRECTION; - } - break; - - default: - err = ENOPROTOOPT; - break; - } - m_freem(m); - break; - - default: - err = ENOPROTOOPT; - break; - } - - return err; -} - -/* - * HCI mbuf tap routine - * - * copy packets to any raw HCI sockets that wish (and are - * permitted) to see them - */ -void -hci_mtap(struct mbuf *m, struct hci_unit *unit) -{ - struct hci_pcb *pcb; - struct mbuf *m0, *ctlmsg, **ctl; - struct sockaddr_bt sa; - uint8_t type; - uint8_t event; - uint16_t opcode; - - KASSERT(m->m_len >= sizeof(type)); - - type = *mtod(m, uint8_t *); - - memset(&sa, 0, sizeof(sa)); - sa.bt_len = sizeof(struct sockaddr_bt); - sa.bt_family = AF_BLUETOOTH; - bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr); - - LIST_FOREACH(pcb, &hci_pcb, hp_next) { - /* - * filter according to source address - */ - if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0 - && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0) - continue; - - /* - * filter according to packet type filter - */ - if (hci_filter_test(type, &pcb->hp_pfilter) == 0) - continue; - - /* - * filter according to event/security filters - */ - switch(type) { - case HCI_EVENT_PKT: - KASSERT(m->m_len >= sizeof(hci_event_hdr_t)); - - event = mtod(m, hci_event_hdr_t *)->event; - - if (hci_filter_test(event, &pcb->hp_efilter) == 0) - continue; - - if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 - && hci_security_check_event(event) == -1) - continue; - break; - - case HCI_CMD_PKT: - KASSERT(m->m_len >= sizeof(hci_cmd_hdr_t)); - - opcode = letoh16(mtod(m, hci_cmd_hdr_t *)->opcode); - - if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 - && hci_security_check_opcode(NULL, opcode) == -1) - continue; - break; - - case HCI_ACL_DATA_PKT: - case HCI_SCO_DATA_PKT: - default: - if ((pcb->hp_flags & HCI_PRIVILEGED) == 0) - continue; - - break; - } - - /* - * create control messages - */ - ctlmsg = NULL; - ctl = &ctlmsg; - if (pcb->hp_flags & HCI_DIRECTION) { - int dir = m->m_flags & M_LINK0 ? 1 : 0; - - *ctl = sbcreatecontrol((void *)&dir, sizeof(dir), - SCM_HCI_DIRECTION, BTPROTO_HCI); - - if (*ctl != NULL) - ctl = &((*ctl)->m_next); - } - - /* - * copy to socket - */ - m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv, - (struct sockaddr *)&sa, m0, ctlmsg)) { - sorwakeup(pcb->hp_socket); - } else { - m_freem(ctlmsg); - m_freem(m0); - } - } -} diff --git a/sys/netbt/hci_unit.c b/sys/netbt/hci_unit.c deleted file mode 100644 index 8a08dfcc2e5..00000000000 --- a/sys/netbt/hci_unit.c +++ /dev/null @@ -1,592 +0,0 @@ -/* $OpenBSD: hci_unit.c,v 1.12 2011/07/06 02:42:28 henning Exp $ */ -/* $NetBSD: hci_unit.c,v 1.12 2008/06/26 14:17:27 plunky Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/conf.h> -#include <sys/device.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/systm.h> - -#include <net/netisr.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> - -struct hci_unit_list hci_unit_list = TAILQ_HEAD_INITIALIZER(hci_unit_list); - -/* - * HCI Input Queue max lengths. - */ -int hci_eventq_max = 20; -int hci_aclrxq_max = 50; -int hci_scorxq_max = 50; -int hci_cmdwait_max = 50; -int hci_scodone_max = 50; - -/* - * This is the default minimum command set supported by older - * devices. Anything conforming to 1.2 spec or later will get - * updated during init. - */ -static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = { - 0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe, - 0x07, 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 -}; - -/* - * bluetooth unit functions - */ - -struct hci_unit * -hci_attach(const struct hci_if *hci_if, struct device *dev, uint16_t flags) -{ - struct hci_unit *unit; - - KASSERT(dev != NULL); - KASSERT(hci_if->enable != NULL); - KASSERT(hci_if->disable != NULL); - KASSERT(hci_if->output_cmd != NULL); - KASSERT(hci_if->output_acl != NULL); - KASSERT(hci_if->output_sco != NULL); - KASSERT(hci_if->get_stats != NULL); - - unit = malloc(sizeof(struct hci_unit), M_BLUETOOTH, M_ZERO | M_WAITOK); - KASSERT(unit != NULL); - - unit->hci_dev = dev; - unit->hci_if = hci_if; - unit->hci_flags = flags; - - mtx_init(&unit->hci_devlock, hci_if->ipl); - unit->hci_init = 0; /* kcondvar_t in NetBSD */ - - IFQ_SET_MAXLEN(&unit->hci_eventq, hci_eventq_max); - IFQ_SET_MAXLEN(&unit->hci_aclrxq, hci_aclrxq_max); - IFQ_SET_MAXLEN(&unit->hci_scorxq, hci_scorxq_max); - IFQ_SET_MAXLEN(&unit->hci_cmdwait, hci_cmdwait_max); - IFQ_SET_MAXLEN(&unit->hci_scodone, hci_scodone_max); - - TAILQ_INIT(&unit->hci_links); - LIST_INIT(&unit->hci_memos); - - mutex_enter(&bt_lock); - TAILQ_INSERT_TAIL(&hci_unit_list, unit, hci_next); - mutex_exit(&bt_lock); - - return unit; -} - -void -hci_detach(struct hci_unit *unit) -{ - - mutex_enter(&bt_lock); - hci_disable(unit); - - TAILQ_REMOVE(&hci_unit_list, unit, hci_next); - mutex_exit(&bt_lock); - - /* mutex_destroy(&unit->hci_devlock) in NetBSD */ - free(unit, M_BLUETOOTH); -} - -int -hci_enable(struct hci_unit *unit) -{ - int err; - - /* - * Block further attempts to enable the interface until the - * previous attempt has completed. - */ - if (unit->hci_flags & BTF_INIT) - return EBUSY; - - /* - * Bluetooth spec says that a device can accept one - * command on power up until they send a Command Status - * or Command Complete event with more information, but - * it seems that some devices cant and prefer to send a - * No-op Command Status packet when they are ready. - */ - unit->hci_num_cmd_pkts = (unit->hci_flags & BTF_POWER_UP_NOOP) ? 0 : 1; - unit->hci_num_acl_pkts = 0; - unit->hci_num_sco_pkts = 0; - - /* - * only allow the basic packet types until - * the features report is in - */ - unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1; - unit->hci_packet_type = unit->hci_acl_mask; - - memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE); - -#ifndef __OpenBSD__ - unit->hci_rxint = softint_establish(SOFTINT_NET, &hci_intr, unit); - if (unit->hci_rxint == NULL) - return EIO; -#endif - - err = (*unit->hci_if->enable)(unit->hci_dev); - if (err) - goto bad1; - - unit->hci_flags |= BTF_RUNNING; - - /* - * Reset the device, this will trigger initialisation - * and wake us up. - */ - unit->hci_flags |= BTF_INIT; - - err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0); - if (err) - goto bad2; - - while (unit->hci_flags & BTF_INIT) { - err = msleep(&unit->hci_init, &bt_lock, PWAIT | PCATCH, - __func__, 5 * hz); - if (err) - goto bad2; - - /* XXX - * "What If", while we were sleeping, the device - * was removed and detached? Ho Hum. - */ - } - - /* - * Attach Bluetooth Device Hub - */ - unit->hci_bthub = config_found(unit->hci_dev, - &unit->hci_bdaddr, NULL); - - return 0; - -bad2: - (*unit->hci_if->disable)(unit->hci_dev); - unit->hci_flags &= ~BTF_RUNNING; -bad1: -#ifndef __OpenBSD__ - softint_disestablish(unit->hci_rxint); - unit->hci_rxint = NULL; -#endif - - return err; -} - -void -hci_disable(struct hci_unit *unit) -{ - struct hci_link *link, *next; - struct hci_memo *memo; - int acl; - - if (unit->hci_bthub) { - struct device *hub; - - hub = unit->hci_bthub; - unit->hci_bthub = NULL; - - mutex_exit(&bt_lock); - config_detach(hub, DETACH_FORCE); - mutex_enter(&bt_lock); - } - -#ifndef __OpenBSD__ - if (unit->hci_rxint) { - softint_disestablish(unit->hci_rxint); - unit->hci_rxint = NULL; - } -#endif - - (*unit->hci_if->disable)(unit->hci_dev); - unit->hci_flags &= ~BTF_RUNNING; - - /* - * close down any links, take care to close SCO first since - * they may depend on ACL links. - */ - for (acl = 0 ; acl < 2 ; acl++) { - next = TAILQ_FIRST(&unit->hci_links); - while ((link = next) != NULL) { - next = TAILQ_NEXT(link, hl_next); - if (acl || link->hl_type != HCI_LINK_ACL) - hci_link_free(link, ECONNABORTED); - } - } - - while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL) - hci_memo_free(memo); - - /* (no need to hold hci_devlock, the driver is disabled) */ - - IF_PURGE(&unit->hci_eventq); - unit->hci_eventqlen = 0; - - IF_PURGE(&unit->hci_aclrxq); - unit->hci_aclrxqlen = 0; - - IF_PURGE(&unit->hci_scorxq); - unit->hci_scorxqlen = 0; - - IF_PURGE(&unit->hci_cmdwait); - IF_PURGE(&unit->hci_scodone); -} - -struct hci_unit * -hci_unit_lookup(bdaddr_t *addr) -{ - struct hci_unit *unit; - - TAILQ_FOREACH(unit, &hci_unit_list, hci_next) { - if ((unit->hci_flags & BTF_UP) == 0) - continue; - - if (bdaddr_same(&unit->hci_bdaddr, addr)) - break; - } - - return unit; -} - -/* - * construct and queue a HCI command packet - */ -int -hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len) -{ - struct mbuf *m; - hci_cmd_hdr_t *p; - - KASSERT(unit != NULL); - - m = m_gethdr(M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - - p = mtod(m, hci_cmd_hdr_t *); - p->type = HCI_CMD_PKT; - p->opcode = htole16(opcode); - p->length = len; - m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t); - M_SETCTX(m, NULL); /* XXX is this needed? */ - - if (len) { - KASSERT(buf != NULL); - - m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf, M_NOWAIT); - if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) { - m_freem(m); - return ENOMEM; - } - } - - DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", device_xname(unit->hci_dev), - HCI_OGF(opcode), HCI_OCF(opcode)); - - /* and send it on */ - if (unit->hci_num_cmd_pkts == 0) - IF_ENQUEUE(&unit->hci_cmdwait, m); - else - hci_output_cmd(unit, m); - - return 0; -} - -/* - * Incoming packet processing. Since the code is single threaded - * in any case (IPL_SOFTNET), we handle it all in one interrupt function - * picking our way through more important packets first so that hopefully - * we will never get clogged up with bulk data. - */ -void -hci_intr(void *arg) -{ - struct hci_unit *unit = arg; - struct mbuf *m; - - mutex_enter(&bt_lock); -another: - mutex_enter(&unit->hci_devlock); - - if (unit->hci_eventqlen > 0) { - IF_DEQUEUE(&unit->hci_eventq, m); - unit->hci_eventqlen--; - mutex_exit(&unit->hci_devlock); - - KASSERT(m != NULL); - - DPRINTFN(10, "(%s) recv event, len = %d\n", - device_xname(unit->hci_dev), m->m_pkthdr.len); - - m->m_flags |= M_LINK0; /* mark incoming packet */ - hci_mtap(m, unit); - hci_event(m, unit); - - goto another; - } - - if (unit->hci_scorxqlen > 0) { - IF_DEQUEUE(&unit->hci_scorxq, m); - unit->hci_scorxqlen--; - mutex_exit(&unit->hci_devlock); - - KASSERT(m != NULL); - - DPRINTFN(10, "(%s) recv SCO, len = %d\n", - device_xname(unit->hci_dev), m->m_pkthdr.len); - - m->m_flags |= M_LINK0; /* mark incoming packet */ - hci_mtap(m, unit); - hci_sco_recv(m, unit); - - goto another; - } - - if (unit->hci_aclrxqlen > 0) { - IF_DEQUEUE(&unit->hci_aclrxq, m); - unit->hci_aclrxqlen--; - mutex_exit(&unit->hci_devlock); - - KASSERT(m != NULL); - - DPRINTFN(10, "(%s) recv ACL, len = %d\n", - device_xname(unit->hci_dev), m->m_pkthdr.len); - - m->m_flags |= M_LINK0; /* mark incoming packet */ - hci_mtap(m, unit); - hci_acl_recv(m, unit); - - goto another; - } - - IF_DEQUEUE(&unit->hci_scodone, m); - if (m != NULL) { - struct hci_link *link; - - mutex_exit(&unit->hci_devlock); - - DPRINTFN(11, "(%s) complete SCO\n", - device_xname(unit->hci_dev)); - - TAILQ_FOREACH(link, &unit->hci_links, hl_next) { - if (link == M_GETCTX(m, struct hci_link *)) { - hci_sco_complete(link, 1); - break; - } - } - - unit->hci_num_sco_pkts++; - m_freem(m); - - goto another; - } - - mutex_exit(&unit->hci_devlock); - mutex_exit(&bt_lock); - - DPRINTFN(10, "done\n"); -} - -/********************************************************************** - * - * IO routines - * - * input & complete routines will be called from device drivers, - * possibly in interrupt context. We return success or failure to - * enable proper accounting but we own the mbuf. - */ - -int -hci_input_event(struct hci_unit *unit, struct mbuf *m) -{ - int rv; - - mutex_enter(&unit->hci_devlock); - - if (unit->hci_eventqlen > hci_eventq_max) { - DPRINTF("(%s) dropped event packet.\n", device_xname(unit->hci_dev)); - m_freem(m); - rv = 0; - } else { - unit->hci_eventqlen++; - IF_ENQUEUE(&unit->hci_eventq, m); - schednetisr(NETISR_BT); - rv = 1; - } - - mutex_exit(&unit->hci_devlock); - return rv; -} - -int -hci_input_acl(struct hci_unit *unit, struct mbuf *m) -{ - int rv; - - mutex_enter(&unit->hci_devlock); - - if (unit->hci_aclrxqlen > hci_aclrxq_max) { - DPRINTF("(%s) dropped ACL packet.\n", device_xname(unit->hci_dev)); - m_freem(m); - rv = 0; - } else { - unit->hci_aclrxqlen++; - IF_ENQUEUE(&unit->hci_aclrxq, m); - schednetisr(NETISR_BT); - rv = 1; - } - - mutex_exit(&unit->hci_devlock); - return rv; -} - -int -hci_input_sco(struct hci_unit *unit, struct mbuf *m) -{ - int rv; - - mutex_enter(&unit->hci_devlock); - - if (unit->hci_scorxqlen > hci_scorxq_max) { - DPRINTF("(%s) dropped SCO packet.\n", device_xname(unit->hci_dev)); - m_freem(m); - rv = 0; - } else { - unit->hci_scorxqlen++; - IF_ENQUEUE(&unit->hci_scorxq, m); - schednetisr(NETISR_BT); - rv = 1; - } - - mutex_exit(&unit->hci_devlock); - return rv; -} - -void -hci_output_cmd(struct hci_unit *unit, struct mbuf *m) -{ - void *arg; - - hci_mtap(m, unit); - - DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", - device_xname(unit->hci_dev), unit->hci_num_cmd_pkts); - - unit->hci_num_cmd_pkts--; - - /* - * If context is set, this was from a HCI raw socket - * and a record needs to be dropped from the sockbuf. - */ - arg = M_GETCTX(m, void *); - if (arg != NULL) - hci_drop(arg); - - (*unit->hci_if->output_cmd)(unit->hci_dev, m); -} - -void -hci_output_acl(struct hci_unit *unit, struct mbuf *m) -{ - - hci_mtap(m, unit); - - DPRINTFN(10, "(%s) num_acl_pkts=%d\n", - device_xname(unit->hci_dev), unit->hci_num_acl_pkts); - - unit->hci_num_acl_pkts--; - (*unit->hci_if->output_acl)(unit->hci_dev, m); -} - -void -hci_output_sco(struct hci_unit *unit, struct mbuf *m) -{ - - hci_mtap(m, unit); - - DPRINTFN(10, "(%s) num_sco_pkts=%d\n", - device_xname(unit->hci_dev), unit->hci_num_sco_pkts); - - unit->hci_num_sco_pkts--; - (*unit->hci_if->output_sco)(unit->hci_dev, m); -} - -int -hci_complete_sco(struct hci_unit *unit, struct mbuf *m) -{ - -#ifndef __OpenBSD__ - if (unit->hci_rxint == NULL) { - DPRINTFN(10, "(%s) complete SCO!\n", device_xname(unit->hci_dev)); - m_freem(m); - return 0; - } -#endif - - mutex_enter(&unit->hci_devlock); - - IF_ENQUEUE(&unit->hci_scodone, m); - schednetisr(NETISR_BT); - - mutex_exit(&unit->hci_devlock); - return 1; -} - -/* - * update num_cmd_pkts and push on pending commands queue - */ -void -hci_num_cmds(struct hci_unit *unit, uint8_t num) -{ - struct mbuf *m; - - unit->hci_num_cmd_pkts = num; - - while (unit->hci_num_cmd_pkts > 0 && !IF_IS_EMPTY(&unit->hci_cmdwait)) { - IF_DEQUEUE(&unit->hci_cmdwait, m); - hci_output_cmd(unit, m); - } -} diff --git a/sys/netbt/l2cap.h b/sys/netbt/l2cap.h deleted file mode 100644 index 8a9b2d52104..00000000000 --- a/sys/netbt/l2cap.h +++ /dev/null @@ -1,490 +0,0 @@ -/* $OpenBSD: l2cap.h,v 1.8 2009/11/21 13:05:32 guenther Exp $ */ -/* $NetBSD: l2cap.h,v 1.8 2008/09/08 23:36:55 gmcgarry Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/*- - * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: l2cap.h,v 1.8 2009/11/21 13:05:32 guenther Exp $ - * $FreeBSD: src/sys/netgraph/bluetooth/include/l2cap.h,v 1.4 2005/08/31 18:13:23 emax Exp $ - */ - -/* - * This file contains everything that application needs to know about - * Link Layer Control and Adaptation Protocol (L2CAP). All information - * was obtained from Bluetooth Specification Books (v1.1 and up) - * - * This file can be included by both kernel and userland applications. - */ - -#ifndef _NETBT_L2CAP_H_ -#define _NETBT_L2CAP_H_ - -#include <sys/types.h> - -/************************************************************************** - ************************************************************************** - ** Common defines and types (L2CAP) - ************************************************************************** - **************************************************************************/ - -/* - * Channel IDs are assigned per machine. So the total number of channels that - * a machine can have open at the same time is 0xffff - 0x0040 = 0xffbf (65471). - * This number does not depend on number of HCI connections. - */ - -#define L2CAP_NULL_CID 0x0000 /* DO NOT USE THIS CID */ -#define L2CAP_SIGNAL_CID 0x0001 /* signaling channel ID */ -#define L2CAP_CLT_CID 0x0002 /* connectionless channel ID */ - /* 0x0003 - 0x003f Reserved */ -#define L2CAP_FIRST_CID 0x0040 /* dynamically alloc. (start) */ -#define L2CAP_LAST_CID 0xffff /* dynamically alloc. (end) */ - -/* L2CAP MTU */ -#define L2CAP_MTU_MINIMUM 48 -#define L2CAP_MTU_DEFAULT 672 -#define L2CAP_MTU_MAXIMUM 0xffff - -/* L2CAP flush and link timeouts */ -#define L2CAP_FLUSH_TIMO_DEFAULT 0xffff /* always retransmit */ -#define L2CAP_LINK_TIMO_DEFAULT 0xffff - -/* L2CAP Command Reject reasons */ -#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000 -#define L2CAP_REJ_MTU_EXCEEDED 0x0001 -#define L2CAP_REJ_INVALID_CID 0x0002 -/* 0x0003 - 0xffff - reserved for future use */ - -/* Protocol/Service Multiplexor (PSM) values */ -#define L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */ -#define L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */ -#define L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */ -#define L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */ -#define L2CAP_PSM_TCS 0x0007 /* TCS cordless */ -#define L2CAP_PSM_BNEP 0x000f /* Bluetooth Network */ - /* Encapsulation Protocol*/ -#define L2CAP_PSM_HID_CNTL 0x0011 /* HID Control */ -#define L2CAP_PSM_HID_INTR 0x0013 /* HID Interrupt */ -#define L2CAP_PSM_ESDP 0x0015 /* Extended Service */ - /* Discovery Profile */ -#define L2CAP_PSM_AVCTP 0x0017 /* Audio/Visual Control */ - /* Transport Protocol */ -#define L2CAP_PSM_AVDTP 0x0019 /* Audio/Visual Distribution */ - /* Transport Protocol */ -/* 0x0019 - 0x1000 - reserved for future use */ - -#define L2CAP_PSM_INVALID(psm) (((psm) & 0x0101) != 0x0001) - -/* L2CAP Connection response command result codes */ -#define L2CAP_SUCCESS 0x0000 -#define L2CAP_PENDING 0x0001 -#define L2CAP_PSM_NOT_SUPPORTED 0x0002 -#define L2CAP_SECURITY_BLOCK 0x0003 -#define L2CAP_NO_RESOURCES 0x0004 -#define L2CAP_TIMEOUT 0xeeee -#define L2CAP_UNKNOWN 0xffff -/* 0x0005 - 0xffff - reserved for future use */ - -/* L2CAP Connection response status codes */ -#define L2CAP_NO_INFO 0x0000 -#define L2CAP_AUTH_PENDING 0x0001 -#define L2CAP_AUTZ_PENDING 0x0002 -/* 0x0003 - 0xffff - reserved for future use */ - -/* L2CAP Configuration response result codes */ -#define L2CAP_UNACCEPTABLE_PARAMS 0x0001 -#define L2CAP_REJECT 0x0002 -#define L2CAP_UNKNOWN_OPTION 0x0003 -/* 0x0003 - 0xffff - reserved for future use */ - -/* L2CAP Configuration options */ -#define L2CAP_OPT_CFLAG_BIT 0x0001 -#define L2CAP_OPT_CFLAG(flags) ((flags) & L2CAP_OPT_CFLAG_BIT) -#define L2CAP_OPT_HINT_BIT 0x80 -#define L2CAP_OPT_HINT(type) ((type) & L2CAP_OPT_HINT_BIT) -#define L2CAP_OPT_HINT_MASK 0x7f -#define L2CAP_OPT_MTU 0x01 -#define L2CAP_OPT_MTU_SIZE sizeof(uint16_t) -#define L2CAP_OPT_FLUSH_TIMO 0x02 -#define L2CAP_OPT_FLUSH_TIMO_SIZE sizeof(uint16_t) -#define L2CAP_OPT_QOS 0x03 -#define L2CAP_OPT_QOS_SIZE sizeof(l2cap_qos_t) -#define L2CAP_OPT_RFC 0x04 -#define L2CAP_OPT_RFC_SIZE sizeof(l2cap_rfc_t) -/* 0x05 - 0xff - reserved for future use */ - -/* L2CAP Information request type codes */ -#define L2CAP_CONNLESS_MTU 0x0001 -#define L2CAP_EXTENDED_FEATURES 0x0002 -/* 0x0003 - 0xffff - reserved for future use */ - -/* L2CAP Information response codes */ -#define L2CAP_NOT_SUPPORTED 0x0001 -/* 0x0002 - 0xffff - reserved for future use */ - -/* L2CAP Quality of Service option */ -typedef struct { - uint8_t flags; /* reserved for future use */ - uint8_t service_type; /* service type */ - uint32_t token_rate; /* bytes per second */ - uint32_t token_bucket_size; /* bytes */ - uint32_t peak_bandwidth; /* bytes per second */ - uint32_t latency; /* microseconds */ - uint32_t delay_variation; /* microseconds */ -} __packed l2cap_qos_t; - -/* L2CAP QoS type */ -#define L2CAP_QOS_NO_TRAFFIC 0x00 -#define L2CAP_QOS_BEST_EFFORT 0x01 /* (default) */ -#define L2CAP_QOS_GUARANTEED 0x02 -/* 0x03 - 0xff - reserved for future use */ - -/* L2CAP Retransmission & Flow Control option */ -typedef struct { - uint8_t mode; /* RFC mode */ - uint8_t window_size; /* bytes */ - uint8_t max_transmit; /* max retransmissions */ - uint16_t retransmit_timo; /* milliseconds */ - uint16_t monitor_timo; /* milliseconds */ - uint16_t max_pdu_size; /* bytes */ -} __packed l2cap_rfc_t; - -/* L2CAP RFC mode */ -#define L2CAP_RFC_BASIC 0x00 /* (default) */ -#define L2CAP_RFC_RETRANSMIT 0x01 -#define L2CAP_RFC_FLOW 0x02 -/* 0x03 - 0xff - reserved for future use */ - -/************************************************************************** - ************************************************************************** - ** Link level defines, headers and types - ************************************************************************** - **************************************************************************/ - -/* L2CAP header */ -typedef struct { - uint16_t length; /* payload size */ - uint16_t dcid; /* destination channel ID */ -} __packed l2cap_hdr_t; - -/* L2CAP ConnectionLess Traffic (dcid == L2CAP_CLT_CID) */ -typedef struct { - uint16_t psm; /* Protocol/Service Multiplexor */ -} __packed l2cap_clt_hdr_t; - -#define L2CAP_CLT_MTU_MAXIMUM \ - (L2CAP_MTU_MAXIMUM - sizeof(l2cap_clt_hdr_t)) - -/* L2CAP Command header (dcid == L2CAP_SIGNAL_CID) */ -typedef struct { - uint8_t code; /* command OpCode */ - uint8_t ident; /* identifier to match request and response */ - uint16_t length; /* command parameters length */ -} __packed l2cap_cmd_hdr_t; - -/* L2CAP Command Reject */ -#define L2CAP_COMMAND_REJ 0x01 -typedef struct { - uint16_t reason; /* reason to reject command */ - uint16_t data[2];/* optional data */ -} __packed l2cap_cmd_rej_cp; - -/* L2CAP Connection Request */ -#define L2CAP_CONNECT_REQ 0x02 -typedef struct { - uint16_t psm; /* Protocol/Service Multiplexor (PSM) */ - uint16_t scid; /* source channel ID */ -} __packed l2cap_con_req_cp; - -/* L2CAP Connection Response */ -#define L2CAP_CONNECT_RSP 0x03 -typedef struct { - uint16_t dcid; /* destination channel ID */ - uint16_t scid; /* source channel ID */ - uint16_t result; /* 0x00 - success */ - uint16_t status; /* more info if result != 0x00 */ -} __packed l2cap_con_rsp_cp; - -/* L2CAP Configuration Request */ -#define L2CAP_CONFIG_REQ 0x04 -typedef struct { - uint16_t dcid; /* destination channel ID */ - uint16_t flags; /* flags */ -/* uint8_t options[] -- options */ -} __packed l2cap_cfg_req_cp; - -/* L2CAP Configuration Response */ -#define L2CAP_CONFIG_RSP 0x05 -typedef struct { - uint16_t scid; /* source channel ID */ - uint16_t flags; /* flags */ - uint16_t result; /* 0x00 - success */ -/* uint8_t options[] -- options */ -} __packed l2cap_cfg_rsp_cp; - -/* L2CAP configuration option */ -typedef struct { - uint8_t type; - uint8_t length; -/* uint8_t value[] -- option value (depends on type) */ -} __packed l2cap_cfg_opt_t; - -/* L2CAP configuration option value */ -typedef union { - uint16_t mtu; /* L2CAP_OPT_MTU */ - uint16_t flush_timo; /* L2CAP_OPT_FLUSH_TIMO */ - l2cap_qos_t qos; /* L2CAP_OPT_QOS */ - l2cap_rfc_t rfc; /* L2CAP_OPT_RFC */ -} l2cap_cfg_opt_val_t; - -/* L2CAP Disconnect Request */ -#define L2CAP_DISCONNECT_REQ 0x06 -typedef struct { - uint16_t dcid; /* destination channel ID */ - uint16_t scid; /* source channel ID */ -} __packed l2cap_discon_req_cp; - -/* L2CAP Disconnect Response */ -#define L2CAP_DISCONNECT_RSP 0x07 -typedef l2cap_discon_req_cp l2cap_discon_rsp_cp; - -/* L2CAP Echo Request */ -#define L2CAP_ECHO_REQ 0x08 -/* No command parameters, only optional data */ - -/* L2CAP Echo Response */ -#define L2CAP_ECHO_RSP 0x09 -#define L2CAP_MAX_ECHO_SIZE \ - (L2CAP_MTU_MAXIMUM - sizeof(l2cap_cmd_hdr_t)) -/* No command parameters, only optional data */ - -/* L2CAP Information Request */ -#define L2CAP_INFO_REQ 0x0a -typedef struct { - uint16_t type; /* requested information type */ -} __packed l2cap_info_req_cp; - -/* L2CAP Information Response */ -#define L2CAP_INFO_RSP 0x0b -typedef struct { - uint16_t type; /* requested information type */ - uint16_t result; /* 0x00 - success */ -/* uint8_t info[] -- info data (depends on type) - * - * L2CAP_CONNLESS_MTU - 2 bytes connectionless MTU - */ -} __packed l2cap_info_rsp_cp; - -typedef union { - /* L2CAP_CONNLESS_MTU */ - struct { - uint16_t mtu; - } __packed mtu; -} l2cap_info_rsp_data_t; - -/************************************************************************** - ************************************************************************** - ** L2CAP Socket Definitions - ************************************************************************** - **************************************************************************/ - -/* Socket options */ -#define SO_L2CAP_IMTU 1 /* incoming MTU */ -#define SO_L2CAP_OMTU 2 /* outgoing MTU */ -#define SO_L2CAP_IQOS 3 /* incoming QoS */ -#define SO_L2CAP_OQOS 4 /* outgoing QoS */ -#define SO_L2CAP_FLUSH 5 /* flush timeout */ -#define SO_L2CAP_LM 6 /* link mode */ - -/* L2CAP link mode flags */ -#define L2CAP_LM_AUTH (1<<0) /* want authentication */ -#define L2CAP_LM_ENCRYPT (1<<1) /* want encryption */ -#define L2CAP_LM_SECURE (1<<2) /* want secured link */ - -#ifdef _KERNEL - -#include <net/if.h> /* for struct ifqueue */ - -LIST_HEAD(l2cap_channel_list, l2cap_channel); - -/* global variables */ -extern struct l2cap_channel_list l2cap_active_list; -extern struct l2cap_channel_list l2cap_listen_list; -extern struct pool l2cap_pdu_pool; -extern struct pool l2cap_req_pool; -extern const l2cap_qos_t l2cap_default_qos; - -/* sysctl variables */ -extern int l2cap_response_timeout; -extern int l2cap_response_extended_timeout; -extern int l2cap_sendspace, l2cap_recvspace; - -/* - * L2CAP Channel - */ -struct l2cap_channel { - struct hci_link *lc_link; /* ACL connection (down) */ - uint16_t lc_state; /* channel state */ - uint16_t lc_flags; /* channel flags */ - uint8_t lc_ident; /* cached request id */ - - uint16_t lc_lcid; /* local channel ID */ - struct sockaddr_bt lc_laddr; /* local address */ - - uint16_t lc_rcid; /* remote channel ID */ - struct sockaddr_bt lc_raddr; /* remote address */ - - int lc_mode; /* link mode */ - uint16_t lc_imtu; /* incoming mtu */ - uint16_t lc_omtu; /* outgoing mtu */ - uint16_t lc_flush; /* flush timeout */ - l2cap_qos_t lc_iqos; /* incoming QoS flow control */ - l2cap_qos_t lc_oqos; /* outgoing Qos flow control */ - - uint8_t lc_pending; /* num of pending PDUs */ - struct ifqueue lc_txq; /* transmit queue */ - - const struct btproto *lc_proto; /* upper layer callbacks */ - void *lc_upper; /* upper layer argument */ - - LIST_ENTRY(l2cap_channel)lc_ncid; /* next channel (ascending CID) */ -}; - -/* l2cap_channel state */ -#define L2CAP_CLOSED 0 /* closed */ -#define L2CAP_WAIT_SEND_CONNECT_REQ 1 /* waiting to send connect request */ -#define L2CAP_WAIT_RECV_CONNECT_RSP 2 /* waiting to recv connect response */ -#define L2CAP_WAIT_SEND_CONNECT_RSP 3 /* waiting to send connect response */ -#define L2CAP_WAIT_CONFIG 4 /* waiting for configuration */ -#define L2CAP_OPEN 5 /* user data transfer state */ -#define L2CAP_WAIT_DISCONNECT 6 /* have sent disconnect request */ - -/* l2cap_channel flags */ -#define L2CAP_SHUTDOWN (1<<0) /* channel is closing */ -#define L2CAP_WAIT_CONFIG_REQ (1<<1) /* waiting for config request */ -#define L2CAP_WAIT_CONFIG_RSP (1<<2) /* waiting for config response */ - -/* - * L2CAP Request - */ -struct l2cap_req { - struct hci_link *lr_link; /* ACL connection */ - struct l2cap_channel *lr_chan; /* channel pointer */ - uint8_t lr_code; /* request code */ - uint8_t lr_id; /* request id */ - struct timeout lr_rtx; /* response timer */ - TAILQ_ENTRY(l2cap_req) lr_next; /* next request on link */ -}; - -/* - * L2CAP Protocol Data Unit - */ -struct l2cap_pdu { - struct l2cap_channel *lp_chan; /* PDU owner */ - struct ifqueue lp_data; /* PDU data */ - TAILQ_ENTRY(l2cap_pdu) lp_next; /* next PDU on link */ - int lp_pending; /* # of fragments pending */ -}; - -/* - * L2CAP function prototypes - */ - -struct socket; -struct mbuf; - -/* l2cap_lower.c */ -void l2cap_close(struct l2cap_channel *, int); -void l2cap_recv_frame(struct mbuf *, struct hci_link *); -int l2cap_start(struct l2cap_channel *); - -/* l2cap_misc.c */ -void l2cap_init(void); -int l2cap_setmode(struct l2cap_channel *); -int l2cap_cid_alloc(struct l2cap_channel *); -struct l2cap_channel *l2cap_cid_lookup(uint16_t); -int l2cap_request_alloc(struct l2cap_channel *, uint8_t); -struct l2cap_req *l2cap_request_lookup(struct hci_link *, uint8_t); -void l2cap_request_free(struct l2cap_req *); -void l2cap_rtx(void *); - -/* l2cap_signal.c */ -void l2cap_recv_signal(struct mbuf *, struct hci_link *); -int l2cap_send_connect_req(struct l2cap_channel *); -int l2cap_send_config_req(struct l2cap_channel *); -int l2cap_send_disconnect_req(struct l2cap_channel *); -int l2cap_send_connect_rsp(struct hci_link *, uint8_t, uint16_t, uint16_t, uint16_t); - -/* l2cap_socket.c */ -int l2cap_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, - struct mbuf *, struct proc *); -int l2cap_ctloutput(int, struct socket *, int, int, struct mbuf **); - -/* l2cap_upper.c */ -int l2cap_attach(struct l2cap_channel **, const struct btproto *, void *); -int l2cap_bind(struct l2cap_channel *, struct sockaddr_bt *); -int l2cap_sockaddr(struct l2cap_channel *, struct sockaddr_bt *); -int l2cap_connect(struct l2cap_channel *, struct sockaddr_bt *); -int l2cap_peeraddr(struct l2cap_channel *, struct sockaddr_bt *); -int l2cap_disconnect(struct l2cap_channel *, int); -int l2cap_detach(struct l2cap_channel **); -int l2cap_listen(struct l2cap_channel *); -int l2cap_send(struct l2cap_channel *, struct mbuf *); -int l2cap_setlinkmode(struct l2cap_channel *, int); -int l2cap_setopt(struct l2cap_channel *, int, struct mbuf *); -int l2cap_getopt(struct l2cap_channel *, int, void *); - -#endif /* _KERNEL */ - -#endif /* _NETBT_L2CAP_H_ */ diff --git a/sys/netbt/l2cap_lower.c b/sys/netbt/l2cap_lower.c deleted file mode 100644 index 24cdb467f57..00000000000 --- a/sys/netbt/l2cap_lower.c +++ /dev/null @@ -1,203 +0,0 @@ -/* $OpenBSD: l2cap_lower.c,v 1.3 2008/11/22 04:42:58 uwe Exp $ */ -/* $NetBSD: l2cap_lower.c,v 1.9 2008/08/05 13:08:31 plunky Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> - -/**************************************************************************** - * - * L2CAP Channel Lower Layer interface - */ - -/* - * L2CAP channel is disconnected, could be: - * - * HCI layer received "Disconnect Complete" event for ACL link - * some Request timed out - * Config failed - * Other end reported invalid CID - * Normal disconnection - * Change link mode failed - */ -void -l2cap_close(struct l2cap_channel *chan, int err) -{ - struct l2cap_pdu *pdu; - struct l2cap_req *req, *n; - - if (chan->lc_state == L2CAP_CLOSED) - return; - - /* - * Since any potential PDU could be half sent we just let it go, - * but disassociate ourselves from it as links deal with ownerless - * PDU's in any case. We could try harder to flush unsent packets - * but maybe its better to leave them in the queue? - */ - TAILQ_FOREACH(pdu, &chan->lc_link->hl_txq, lp_next) { - if (pdu->lp_chan == chan) - pdu->lp_chan = NULL; - } - - /* - * and clear any outstanding requests.. - */ - req = TAILQ_FIRST(&chan->lc_link->hl_reqs); - while (req != NULL) { - n = TAILQ_NEXT(req, lr_next); - if (req->lr_chan == chan) - l2cap_request_free(req); - - req = n; - } - - chan->lc_pending = 0; - chan->lc_state = L2CAP_CLOSED; - hci_acl_close(chan->lc_link, err); - chan->lc_link = NULL; - - (*chan->lc_proto->disconnected)(chan->lc_upper, err); -} - -/* - * Process incoming L2CAP frame from ACL link. We take off the B-Frame - * header (which is present in all packets), verify the data length - * and distribute the rest of the frame to the relevant channel - * handler. - */ -void -l2cap_recv_frame(struct mbuf *m, struct hci_link *link) -{ - struct l2cap_channel *chan; - l2cap_hdr_t hdr; - - m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); - m_adj(m, sizeof(hdr)); - - hdr.length = letoh16(hdr.length); - hdr.dcid = letoh16(hdr.dcid); - - DPRINTFN(5, "(%s) received packet (%d bytes)\n", - device_xname(link->hl_unit->hci_dev), hdr.length); - - if (hdr.length != m->m_pkthdr.len) - goto failed; - - if (hdr.dcid == L2CAP_SIGNAL_CID) { - l2cap_recv_signal(m, link); - return; - } - - if (hdr.dcid == L2CAP_CLT_CID) { - m_freem(m); /* TODO */ - return; - } - - chan = l2cap_cid_lookup(hdr.dcid); - if (chan != NULL && chan->lc_link == link - && chan->lc_imtu >= hdr.length - && chan->lc_state == L2CAP_OPEN) { - (*chan->lc_proto->input)(chan->lc_upper, m); - return; - } - - DPRINTF("(%s) invalid L2CAP packet dropped, CID #%d, length %d\n", - device_xname(link->hl_unit->hci_dev), hdr.dcid, hdr.length); - -failed: - m_freem(m); -} - -/* - * Start another L2CAP packet on its way. This is called from l2cap_send - * (when no PDU is pending) and hci_acl_start (when PDU has been placed on - * device queue). Thus we can have more than one PDU waiting at the device - * if space is available but no single channel will hog the link. - */ -int -l2cap_start(struct l2cap_channel *chan) -{ - struct mbuf *m; - int err = 0; - - if (chan->lc_state != L2CAP_OPEN) - return 0; - - if (IF_IS_EMPTY(&chan->lc_txq)) { - DPRINTFN(5, "no data, pending = %d\n", chan->lc_pending); - /* - * If we are just waiting for the queue to flush - * and it has, we may disconnect.. - */ - if (chan->lc_flags & L2CAP_SHUTDOWN - && chan->lc_pending == 0) { - chan->lc_state = L2CAP_WAIT_DISCONNECT; - err = l2cap_send_disconnect_req(chan); - if (err) - l2cap_close(chan, err); - } - - return err; - } - - /* - * We could check QoS/RFC mode here and optionally not send - * the packet if we are not ready for any reason - * - * Also to support flush timeout then we might want to start - * the timer going? (would need to keep some kind of record - * of packets sent, possibly change it so that we allocate - * the l2cap_pdu and fragment the packet, then hand it down - * and get it back when its completed). Hm. - */ - - IF_DEQUEUE(&chan->lc_txq, m); - - KASSERT(chan->lc_link != NULL); - KASSERT(m != NULL); - - DPRINTFN(5, "CID #%d sending packet (%d bytes)\n", - chan->lc_lcid, m->m_pkthdr.len); - - chan->lc_pending++; - return hci_acl_send(m, chan->lc_link, chan); -} diff --git a/sys/netbt/l2cap_misc.c b/sys/netbt/l2cap_misc.c deleted file mode 100644 index 650f34910c8..00000000000 --- a/sys/netbt/l2cap_misc.c +++ /dev/null @@ -1,262 +0,0 @@ -/* $OpenBSD: l2cap_misc.c,v 1.8 2010/07/29 14:40:47 blambert Exp $ */ -/* $NetBSD: l2cap_misc.c,v 1.6 2008/04/24 11:38:37 ad Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/pool.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> - -struct l2cap_channel_list - l2cap_active_list = LIST_HEAD_INITIALIZER(l2cap_active_list); -struct l2cap_channel_list - l2cap_listen_list = LIST_HEAD_INITIALIZER(l2cap_listen_list); - -struct pool l2cap_req_pool; -struct pool l2cap_pdu_pool; - -const l2cap_qos_t l2cap_default_qos = { - 0, /* flags */ - L2CAP_QOS_BEST_EFFORT, /* service type */ - 0x00000000, /* token rate */ - 0x00000000, /* token bucket size */ - 0x00000000, /* peak bandwidth */ - 0xffffffff, /* latency */ - 0xffffffff /* delay variation */ -}; - -/* - * L2CAP request timeouts - */ -int l2cap_response_timeout = 30; /* seconds */ -int l2cap_response_extended_timeout = 180; /* seconds */ - -void -l2cap_init(void) -{ - pool_init(&l2cap_req_pool, sizeof(struct l2cap_req), 0, 0, 0, - "l2cap_req", NULL); - pool_init(&l2cap_pdu_pool, sizeof(struct l2cap_pdu), 0, 0, 0, - "l2cap_pdu", NULL); -} - -/* - * Set Link Mode on channel - */ -int -l2cap_setmode(struct l2cap_channel *chan) -{ - - KASSERT(chan != NULL); - KASSERT(chan->lc_link != NULL); - - DPRINTF("(%s) CID #%d, auth %s, encrypt %s, secure %s\n", - device_xname(chan->lc_link->hl_unit->hci_dev), chan->lc_lcid, - (chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"), - (chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"), - (chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no")); - - if (chan->lc_mode & L2CAP_LM_AUTH) - chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ; - - if (chan->lc_mode & L2CAP_LM_ENCRYPT) - chan->lc_link->hl_flags |= HCI_LINK_ENCRYPT_REQ; - - if (chan->lc_mode & L2CAP_LM_SECURE) - chan->lc_link->hl_flags |= HCI_LINK_SECURE_REQ; - - return hci_acl_setmode(chan->lc_link); -} - -/* - * Allocate a new Request structure & ID and set the timer going - */ -int -l2cap_request_alloc(struct l2cap_channel *chan, uint8_t code) -{ - struct hci_link *link = chan->lc_link; - struct l2cap_req *req; - int next_id; - - if (link == NULL) - return ENETDOWN; - - /* find next ID (0 is not allowed) */ - next_id = link->hl_lastid + 1; - if (next_id > 0xff) - next_id = 1; - - /* Ouroboros check */ - req = TAILQ_FIRST(&link->hl_reqs); - if (req && req->lr_id == next_id) - return ENFILE; - - req = pool_get(&l2cap_req_pool, PR_NOWAIT); - if (req == NULL) - return ENOMEM; - - req->lr_id = link->hl_lastid = next_id; - - req->lr_code = code; - req->lr_chan = chan; - req->lr_link = link; - - timeout_set(&req->lr_rtx, l2cap_rtx, req); - timeout_add_sec(&req->lr_rtx, l2cap_response_timeout); - - TAILQ_INSERT_TAIL(&link->hl_reqs, req, lr_next); - - return 0; -} - -/* - * Find a running request for this link - */ -struct l2cap_req * -l2cap_request_lookup(struct hci_link *link, uint8_t id) -{ - struct l2cap_req *req; - - TAILQ_FOREACH(req, &link->hl_reqs, lr_next) { - if (req->lr_id == id) - return req; - } - - return NULL; -} - -/* - * Halt and free a request - */ -void -l2cap_request_free(struct l2cap_req *req) -{ - struct hci_link *link = req->lr_link; - - if (timeout_triggered(&req->lr_rtx)) - return; - timeout_del(&req->lr_rtx); - - TAILQ_REMOVE(&link->hl_reqs, req, lr_next); - pool_put(&l2cap_req_pool, req); -} - -/* - * Response Timeout eXpired - * - * No response to our request, so deal with it as best we can. - * - * XXX should try again at least with ertx? - */ -void -l2cap_rtx(void *arg) -{ - struct l2cap_req *req = arg; - struct l2cap_channel *chan; - - mutex_enter(&bt_lock); - - chan = req->lr_chan; - DPRINTF("cid %d, ident %d\n", (chan ? chan->lc_lcid : 0), req->lr_id); - - l2cap_request_free(req); - - if (chan && chan->lc_state != L2CAP_CLOSED) - l2cap_close(chan, ETIMEDOUT); - - mutex_exit(&bt_lock); -} - -/* - * Allocate next available CID to channel. We keep a single - * ordered list of channels, so find the first gap. - * - * If this turns out to be not enough (!), could use a - * list per HCI unit.. - */ -int -l2cap_cid_alloc(struct l2cap_channel *chan) -{ - struct l2cap_channel *used, *prev = NULL; - uint16_t cid = L2CAP_FIRST_CID; - - if (chan->lc_lcid != L2CAP_NULL_CID || chan->lc_state != L2CAP_CLOSED) - return EISCONN; - - LIST_FOREACH(used, &l2cap_active_list, lc_ncid) { - if (used->lc_lcid > cid) - break; /* found our gap */ - - KASSERT(used->lc_lcid == cid); - cid++; - - if (cid == L2CAP_LAST_CID) - return ENFILE; - - prev = used; /* for insert after */ - } - - chan->lc_lcid = cid; - - if (prev) - LIST_INSERT_AFTER(prev, chan, lc_ncid); - else - LIST_INSERT_HEAD(&l2cap_active_list, chan, lc_ncid); - - return 0; -} - -/* - * Find channel with CID - */ -struct l2cap_channel * -l2cap_cid_lookup(uint16_t cid) -{ - struct l2cap_channel *chan; - - LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) { - if (chan->lc_lcid == cid) - return chan; - - if (chan->lc_lcid > cid) - return NULL; - } - - return NULL; -} diff --git a/sys/netbt/l2cap_signal.c b/sys/netbt/l2cap_signal.c deleted file mode 100644 index 5d4f0dc6da5..00000000000 --- a/sys/netbt/l2cap_signal.c +++ /dev/null @@ -1,1152 +0,0 @@ -/* $OpenBSD: l2cap_signal.c,v 1.6 2010/07/02 02:40:16 blambert Exp $ */ -/* $NetBSD: l2cap_signal.c,v 1.9 2007/11/10 23:12:23 plunky Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> - -/******************************************************************************* - * - * L2CAP Signal processing - */ - -static void l2cap_recv_command_rej(struct mbuf *, struct hci_link *); -static void l2cap_recv_connect_req(struct mbuf *, struct hci_link *); -static void l2cap_recv_connect_rsp(struct mbuf *, struct hci_link *); -static void l2cap_recv_config_req(struct mbuf *, struct hci_link *); -static void l2cap_recv_config_rsp(struct mbuf *, struct hci_link *); -static void l2cap_recv_disconnect_req(struct mbuf *, struct hci_link *); -static void l2cap_recv_disconnect_rsp(struct mbuf *, struct hci_link *); -static void l2cap_recv_info_req(struct mbuf *, struct hci_link *); -static int l2cap_send_signal(struct hci_link *, uint8_t, uint8_t, uint16_t, void *); -static int l2cap_send_command_rej(struct hci_link *, uint8_t, uint32_t, ...); - -/* - * process incoming signal packets (CID 0x0001). Can contain multiple - * requests/responses. - */ -void -l2cap_recv_signal(struct mbuf *m, struct hci_link *link) -{ - l2cap_cmd_hdr_t cmd; - - for(;;) { - if (m->m_pkthdr.len == 0) - goto finish; - - if (m->m_pkthdr.len < sizeof(cmd)) - goto reject; - - m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); - cmd.length = letoh16(cmd.length); - - if (m->m_pkthdr.len < sizeof(cmd) + cmd.length) - goto reject; - - DPRINTFN(2, "(%s) code %d, ident %d, len %d\n", - device_xname(link->hl_unit->hci_dev), - cmd.code, cmd.ident, cmd.length); - - switch (cmd.code) { - case L2CAP_COMMAND_REJ: - if (cmd.length > sizeof(l2cap_cmd_rej_cp)) - goto finish; - - l2cap_recv_command_rej(m, link); - break; - - case L2CAP_CONNECT_REQ: - if (cmd.length != sizeof(l2cap_con_req_cp)) - goto reject; - - l2cap_recv_connect_req(m, link); - break; - - case L2CAP_CONNECT_RSP: - if (cmd.length != sizeof(l2cap_con_rsp_cp)) - goto finish; - - l2cap_recv_connect_rsp(m, link); - break; - - case L2CAP_CONFIG_REQ: - l2cap_recv_config_req(m, link); - break; - - case L2CAP_CONFIG_RSP: - l2cap_recv_config_rsp(m, link); - break; - - case L2CAP_DISCONNECT_REQ: - if (cmd.length != sizeof(l2cap_discon_req_cp)) - goto reject; - - l2cap_recv_disconnect_req(m, link); - break; - - case L2CAP_DISCONNECT_RSP: - if (cmd.length != sizeof(l2cap_discon_rsp_cp)) - goto finish; - - l2cap_recv_disconnect_rsp(m, link); - break; - - case L2CAP_ECHO_REQ: - m_adj(m, sizeof(cmd) + cmd.length); - l2cap_send_signal(link, L2CAP_ECHO_RSP, cmd.ident, - 0, NULL); - break; - - case L2CAP_ECHO_RSP: - m_adj(m, sizeof(cmd) + cmd.length); - break; - - case L2CAP_INFO_REQ: - if (cmd.length != sizeof(l2cap_info_req_cp)) - goto reject; - - l2cap_recv_info_req(m, link); - break; - - case L2CAP_INFO_RSP: - m_adj(m, sizeof(cmd) + cmd.length); - break; - - default: - goto reject; - } - } - -#ifdef DIAGNOSTIC - panic("impossible!"); -#endif - -reject: - l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_NOT_UNDERSTOOD); -finish: - m_freem(m); -} - -/* - * Process Received Command Reject. For now we dont try to recover gracefully - * from this, it probably means that the link is garbled or the other end is - * insufficiently capable of handling normal traffic. (not *my* fault, no way!) - */ -static void -l2cap_recv_command_rej(struct mbuf *m, struct hci_link *link) -{ - struct l2cap_req *req; - struct l2cap_channel *chan; - l2cap_cmd_hdr_t cmd; - l2cap_cmd_rej_cp cp; - - m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); - m_adj(m, sizeof(cmd)); - - cmd.length = letoh16(cmd.length); - - m_copydata(m, 0, cmd.length, (caddr_t)&cp); - m_adj(m, cmd.length); - - req = l2cap_request_lookup(link, cmd.ident); - if (req == NULL) - return; - - switch (letoh16(cp.reason)) { - case L2CAP_REJ_NOT_UNDERSTOOD: - /* - * I dont know what to do, just move up the timeout - */ - timeout_add(&req->lr_rtx, 0); - break; - - case L2CAP_REJ_MTU_EXCEEDED: - /* - * I didnt send any commands over L2CAP_MTU_MINIMUM size, but.. - * - * XXX maybe we should resend this, instead? - */ - link->hl_mtu = letoh16(cp.data[0]); - timeout_add(&req->lr_rtx, 0); - break; - - case L2CAP_REJ_INVALID_CID: - /* - * Well, if they dont have such a channel then our channel is - * most likely closed. Make it so. - */ - chan = req->lr_chan; - l2cap_request_free(req); - if (chan != NULL && chan->lc_state != L2CAP_CLOSED) - l2cap_close(chan, ECONNABORTED); - - break; - - default: - UNKNOWN(letoh16(cp.reason)); - break; - } -} - -/* - * Process Received Connect Request. Find listening channel matching - * psm & addr and ask upper layer for a new channel. - */ -static void -l2cap_recv_connect_req(struct mbuf *m, struct hci_link *link) -{ - struct sockaddr_bt laddr, raddr; - struct l2cap_channel *chan, *new; - l2cap_cmd_hdr_t cmd; - l2cap_con_req_cp cp; - int err; - - /* extract cmd */ - m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); - m_adj(m, sizeof(cmd)); - - /* extract request */ - m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); - m_adj(m, sizeof(cp)); - - cp.scid = letoh16(cp.scid); - cp.psm = letoh16(cp.psm); - - memset(&laddr, 0, sizeof(struct sockaddr_bt)); - laddr.bt_len = sizeof(struct sockaddr_bt); - laddr.bt_family = AF_BLUETOOTH; - laddr.bt_psm = cp.psm; - bdaddr_copy(&laddr.bt_bdaddr, &link->hl_unit->hci_bdaddr); - - memset(&raddr, 0, sizeof(struct sockaddr_bt)); - raddr.bt_len = sizeof(struct sockaddr_bt); - raddr.bt_family = AF_BLUETOOTH; - raddr.bt_psm = cp.psm; - bdaddr_copy(&raddr.bt_bdaddr, &link->hl_bdaddr); - - LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) { - if (chan->lc_laddr.bt_psm != laddr.bt_psm - && chan->lc_laddr.bt_psm != L2CAP_PSM_ANY) - continue; - - if (!bdaddr_same(&laddr.bt_bdaddr, &chan->lc_laddr.bt_bdaddr) - && bdaddr_any(&chan->lc_laddr.bt_bdaddr) == 0) - continue; - - new= (*chan->lc_proto->newconn)(chan->lc_upper, &laddr, &raddr); - if (new == NULL) - continue; - - err = l2cap_cid_alloc(new); - if (err) { - l2cap_send_connect_rsp(link, cmd.ident, - 0, cp.scid, - L2CAP_NO_RESOURCES); - - (*new->lc_proto->disconnected)(new->lc_upper, err); - return; - } - - new->lc_link = hci_acl_open(link->hl_unit, &link->hl_bdaddr); - KASSERT(new->lc_link == link); - - new->lc_rcid = cp.scid; - new->lc_ident = cmd.ident; - - memcpy(&new->lc_laddr, &laddr, sizeof(struct sockaddr_bt)); - memcpy(&new->lc_raddr, &raddr, sizeof(struct sockaddr_bt)); - - new->lc_mode = chan->lc_mode; - - err = l2cap_setmode(new); - if (err == EINPROGRESS) { - new->lc_state = L2CAP_WAIT_SEND_CONNECT_RSP; - (*new->lc_proto->connecting)(new->lc_upper); - return; - } - if (err) { - new->lc_state = L2CAP_CLOSED; - hci_acl_close(link, err); - new->lc_link = NULL; - - l2cap_send_connect_rsp(link, cmd.ident, - 0, cp.scid, - L2CAP_NO_RESOURCES); - - (*new->lc_proto->disconnected)(new->lc_upper, err); - return; - } - - err = l2cap_send_connect_rsp(link, cmd.ident, - new->lc_lcid, new->lc_rcid, - L2CAP_SUCCESS); - if (err) { - l2cap_close(new, err); - return; - } - - new->lc_state = L2CAP_WAIT_CONFIG; - new->lc_flags |= (L2CAP_WAIT_CONFIG_REQ | L2CAP_WAIT_CONFIG_RSP); - err = l2cap_send_config_req(new); - if (err) - l2cap_close(new, err); - - return; - } - - l2cap_send_connect_rsp(link, cmd.ident, - 0, cp.scid, - L2CAP_PSM_NOT_SUPPORTED); -} - -/* - * Process Received Connect Response. - */ -static void -l2cap_recv_connect_rsp(struct mbuf *m, struct hci_link *link) -{ - l2cap_cmd_hdr_t cmd; - l2cap_con_rsp_cp cp; - struct l2cap_req *req; - struct l2cap_channel *chan; - - m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); - m_adj(m, sizeof(cmd)); - - m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); - m_adj(m, sizeof(cp)); - - cp.scid = letoh16(cp.scid); - cp.dcid = letoh16(cp.dcid); - cp.result = letoh16(cp.result); - - req = l2cap_request_lookup(link, cmd.ident); - if (req == NULL || req->lr_code != L2CAP_CONNECT_REQ) - return; - - chan = req->lr_chan; - if (chan != NULL && chan->lc_lcid != cp.scid) - return; - - if (chan == NULL || chan->lc_state != L2CAP_WAIT_RECV_CONNECT_RSP) { - l2cap_request_free(req); - return; - } - - switch (cp.result) { - case L2CAP_SUCCESS: - /* - * Ok, at this point we have a connection to the other party. We - * could indicate upstream that we are ready for business and - * wait for a "Configure Channel Request" but I'm not so sure - * that is required in our case - we will proceed directly to - * sending our config request. We set two state bits because in - * the config state we are waiting for requests and responses. - */ - l2cap_request_free(req); - chan->lc_rcid = cp.dcid; - chan->lc_state = L2CAP_WAIT_CONFIG; - chan->lc_flags |= (L2CAP_WAIT_CONFIG_REQ | L2CAP_WAIT_CONFIG_RSP); - l2cap_send_config_req(chan); - break; - - case L2CAP_PENDING: - /* XXX dont release request, should start eRTX timeout? */ - (*chan->lc_proto->connecting)(chan->lc_upper); - break; - - case L2CAP_PSM_NOT_SUPPORTED: - case L2CAP_SECURITY_BLOCK: - case L2CAP_NO_RESOURCES: - default: - l2cap_request_free(req); - l2cap_close(chan, ECONNREFUSED); - break; - } -} - -/* - * Process Received Config Request. - */ -static void -l2cap_recv_config_req(struct mbuf *m, struct hci_link *link) -{ - uint8_t buf[L2CAP_MTU_MINIMUM]; - l2cap_cmd_hdr_t cmd; - l2cap_cfg_req_cp cp; - l2cap_cfg_opt_t opt; - l2cap_cfg_opt_val_t val; - l2cap_cfg_rsp_cp rp; - struct l2cap_channel *chan; - int left, len; - - m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); - m_adj(m, sizeof(cmd)); - left = letoh16(cmd.length); - - if (left < sizeof(cp)) - goto reject; - - m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); - m_adj(m, sizeof(cp)); - left -= sizeof(cp); - - cp.dcid = letoh16(cp.dcid); - cp.flags = letoh16(cp.flags); - - chan = l2cap_cid_lookup(cp.dcid); - if (chan == NULL || chan->lc_link != link - || chan->lc_state != L2CAP_WAIT_CONFIG - || (chan->lc_flags & L2CAP_WAIT_CONFIG_REQ) == 0) { - /* XXX we should really accept reconfiguration requests */ - l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_INVALID_CID, - L2CAP_NULL_CID, cp.dcid); - goto out; - } - - /* ready our response packet */ - rp.scid = htole16(chan->lc_rcid); - rp.flags = 0; /* "No Continuation" */ - rp.result = L2CAP_SUCCESS; - len = sizeof(rp); - - /* - * Process the packet. We build the return packet on the fly adding any - * unacceptable parameters as we go. As we can only return one result, - * unknown option takes precedence so we start our return packet anew - * and ignore option values thereafter as they will be re-sent. - * - * Since we do not support enough options to make overflowing the min - * MTU size an issue in normal use, we just reject config requests that - * make that happen. This could be because options are repeated or the - * packet is corrupted in some way. - * - * If unknown option types threaten to overflow the packet, we just - * ignore them. We can deny them next time. - */ - while (left > 0) { - if (left < sizeof(opt)) - goto reject; - - m_copydata(m, 0, sizeof(opt), (caddr_t)&opt); - m_adj(m, sizeof(opt)); - left -= sizeof(opt); - - if (left < opt.length) - goto reject; - - switch(opt.type & L2CAP_OPT_HINT_MASK) { - case L2CAP_OPT_MTU: - if (rp.result == L2CAP_UNKNOWN_OPTION) - break; - - if (opt.length != L2CAP_OPT_MTU_SIZE) - goto reject; - - m_copydata(m, 0, L2CAP_OPT_MTU_SIZE, (caddr_t)&val); - val.mtu = letoh16(val.mtu); - - /* - * XXX how do we know what the minimum acceptable MTU is - * for a channel? Spec says some profiles have a higher - * minimum but I have no way to find that out at this - * juncture.. - */ - if (val.mtu < L2CAP_MTU_MINIMUM) { - if (len + sizeof(opt) + L2CAP_OPT_MTU_SIZE > sizeof(buf)) - goto reject; - - rp.result = L2CAP_UNACCEPTABLE_PARAMS; - memcpy(buf + len, &opt, sizeof(opt)); - len += sizeof(opt); - val.mtu = htole16(L2CAP_MTU_MINIMUM); - memcpy(buf + len, &val, L2CAP_OPT_MTU_SIZE); - len += L2CAP_OPT_MTU_SIZE; - } else - chan->lc_omtu = val.mtu; - - break; - - case L2CAP_OPT_FLUSH_TIMO: - if (rp.result == L2CAP_UNKNOWN_OPTION) - break; - - if (opt.length != L2CAP_OPT_FLUSH_TIMO_SIZE) - goto reject; - - /* - * I think that this is informational only - he is - * informing us of the flush timeout he will be using. - * I dont think this affects us in any significant way, - * so just ignore this value for now. - */ - break; - - case L2CAP_OPT_QOS: - if (rp.result == L2CAP_UNKNOWN_OPTION) - break; - - if (opt.length != L2CAP_OPT_QOS_SIZE) - goto reject; - - m_copydata(m, 0, L2CAP_OPT_QOS_SIZE, (caddr_t)&val); - if (val.qos.service_type == L2CAP_QOS_NO_TRAFFIC || - val.qos.service_type == L2CAP_QOS_BEST_EFFORT) - /* - * In accordance with the spec, we choose to - * ignore the fields an provide no response. - */ - break; - - if (len + sizeof(opt) + L2CAP_OPT_QOS_SIZE > sizeof(buf)) - goto reject; - - if (val.qos.service_type != L2CAP_QOS_GUARANTEED) { - /* - * Instead of sending an "unacceptable - * parameters" response, treat this as an - * unknown option and include the option - * value in the response. - */ - rp.result = L2CAP_UNKNOWN_OPTION; - } else { - /* - * According to the spec, we must return - * specific values for wild card parameters. - * I don't know what to return without lying, - * so return "unacceptable parameters" and - * specify the preferred service type as - * "Best Effort". - */ - rp.result = L2CAP_UNACCEPTABLE_PARAMS; - val.qos.service_type = L2CAP_QOS_BEST_EFFORT; - } - - memcpy(buf + len, &opt, sizeof(opt)); - len += sizeof(opt); - memcpy(buf + len, &val, L2CAP_OPT_QOS_SIZE); - len += L2CAP_OPT_QOS_SIZE; - break; - - default: - /* ignore hints */ - if (opt.type & L2CAP_OPT_HINT_BIT) - break; - - /* unknown options supersede all else */ - if (rp.result != L2CAP_UNKNOWN_OPTION) { - rp.result = L2CAP_UNKNOWN_OPTION; - len = sizeof(rp); - } - - /* ignore if it doesn't fit */ - if (len + sizeof(opt) > sizeof(buf)) - break; - - /* return unknown option type, but no data */ - buf[len++] = opt.type; - buf[len++] = 0; - break; - } - - m_adj(m, opt.length); - left -= opt.length; - } - - rp.result = htole16(rp.result); - memcpy(buf, &rp, sizeof(rp)); - l2cap_send_signal(link, L2CAP_CONFIG_RSP, cmd.ident, len, buf); - - if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0 - && rp.result == letoh16(L2CAP_SUCCESS)) { - - chan->lc_flags &= ~L2CAP_WAIT_CONFIG_REQ; - - if ((chan->lc_flags & L2CAP_WAIT_CONFIG_RSP) == 0) { - chan->lc_state = L2CAP_OPEN; - /* XXX how to distinguish REconfiguration? */ - (*chan->lc_proto->connected)(chan->lc_upper); - } - } - return; - -reject: - l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_NOT_UNDERSTOOD); -out: - m_adj(m, left); -} - -/* - * Process Received Config Response. - */ -static void -l2cap_recv_config_rsp(struct mbuf *m, struct hci_link *link) -{ - l2cap_cmd_hdr_t cmd; - l2cap_cfg_rsp_cp cp; - l2cap_cfg_opt_t opt; - l2cap_cfg_opt_val_t val; - struct l2cap_req *req; - struct l2cap_channel *chan; - int left; - - m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); - m_adj(m, sizeof(cmd)); - left = letoh16(cmd.length); - - if (left < sizeof(cp)) - goto out; - - m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); - m_adj(m, sizeof(cp)); - left -= sizeof(cp); - - cp.scid = letoh16(cp.scid); - cp.flags = letoh16(cp.flags); - cp.result = letoh16(cp.result); - - req = l2cap_request_lookup(link, cmd.ident); - if (req == NULL || req->lr_code != L2CAP_CONFIG_REQ) - goto out; - - chan = req->lr_chan; - if (chan != NULL && chan->lc_lcid != cp.scid) - goto out; - - l2cap_request_free(req); - - if (chan == NULL || chan->lc_state != L2CAP_WAIT_CONFIG - || (chan->lc_flags & L2CAP_WAIT_CONFIG_RSP) == 0) - goto out; - - if ((cp.flags & L2CAP_OPT_CFLAG_BIT)) { - l2cap_cfg_req_cp rp; - - /* - * They have more to tell us and want another ID to - * use, so send an empty config request - */ - if (l2cap_request_alloc(chan, L2CAP_CONFIG_REQ)) - goto discon; - - rp.dcid = htole16(cp.scid); - rp.flags = 0; - - if (l2cap_send_signal(link, L2CAP_CONFIG_REQ, link->hl_lastid, - sizeof(rp), &rp)) - goto discon; - } - - switch(cp.result) { - case L2CAP_SUCCESS: - /* - * If continuation flag was not set, our config request was - * accepted. We may have to wait for their config request to - * complete, so check that but otherwise we are open - * - * There may be 'advisory' values in the packet but we just - * ignore those.. - */ - if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0) { - chan->lc_flags &= ~L2CAP_WAIT_CONFIG_RSP; - - if ((chan->lc_flags & L2CAP_WAIT_CONFIG_REQ) == 0) { - chan->lc_state = L2CAP_OPEN; - /* XXX how to distinguish REconfiguration? */ - (*chan->lc_proto->connected)(chan->lc_upper); - } - } - goto out; - - case L2CAP_UNACCEPTABLE_PARAMS: - /* - * Packet contains unacceptable parameters with preferred values - */ - while (left > 0) { - if (left < sizeof(opt)) - goto discon; - - m_copydata(m, 0, sizeof(opt), (caddr_t)&opt); - m_adj(m, sizeof(opt)); - left -= sizeof(opt); - - if (left < opt.length) - goto discon; - - switch (opt.type) { - case L2CAP_OPT_MTU: - if (opt.length != L2CAP_OPT_MTU_SIZE) - goto discon; - - m_copydata(m, 0, L2CAP_OPT_MTU_SIZE, (caddr_t)&val); - chan->lc_imtu = letoh16(val.mtu); - if (chan->lc_imtu < L2CAP_MTU_MINIMUM) - chan->lc_imtu = L2CAP_MTU_DEFAULT; - break; - - case L2CAP_OPT_FLUSH_TIMO: - if (opt.length != L2CAP_OPT_FLUSH_TIMO_SIZE) - goto discon; - - /* - * Spec says: If we cannot honor proposed value, - * either disconnect or try again with original - * value. I can't really see why they want to - * interfere with OUR flush timeout in any case - * so we just punt for now. - */ - goto discon; - - case L2CAP_OPT_QOS: - break; - - default: - UNKNOWN(opt.type); - goto discon; - } - - m_adj(m, opt.length); - left -= opt.length; - } - - if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0) - l2cap_send_config_req(chan); /* no state change */ - - goto out; - - case L2CAP_REJECT: - goto discon; - - case L2CAP_UNKNOWN_OPTION: - /* - * Packet contains options not understood. Turn off unknown - * options by setting them to default values (means they will - * not be requested again). - * - * If our option was already off then fail (paranoia?) - * - * XXX Should we consider that options were set for a reason? - */ - while (left > 0) { - if (left < sizeof(opt)) - goto discon; - - m_copydata(m, 0, sizeof(opt), (caddr_t)&opt); - m_adj(m, sizeof(opt)); - left -= sizeof(opt); - - if (left < opt.length) - goto discon; - - m_adj(m, opt.length); - left -= opt.length; - - switch(opt.type) { - case L2CAP_OPT_MTU: - if (chan->lc_imtu == L2CAP_MTU_DEFAULT) - goto discon; - - chan->lc_imtu = L2CAP_MTU_DEFAULT; - break; - - case L2CAP_OPT_FLUSH_TIMO: - if (chan->lc_flush == L2CAP_FLUSH_TIMO_DEFAULT) - goto discon; - - chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT; - break; - - case L2CAP_OPT_QOS: - break; - - default: - UNKNOWN(opt.type); - goto discon; - } - } - - if ((cp.flags & L2CAP_OPT_CFLAG_BIT) == 0) - l2cap_send_config_req(chan); /* no state change */ - - goto out; - - default: - UNKNOWN(cp.result); - goto discon; - } - - DPRINTF("how did I get here!?\n"); - -discon: - l2cap_send_disconnect_req(chan); - l2cap_close(chan, ECONNABORTED); - -out: - m_adj(m, left); -} - -/* - * Process Received Disconnect Request. We must validate scid and dcid - * just in case but otherwise this connection is finished. - */ -static void -l2cap_recv_disconnect_req(struct mbuf *m, struct hci_link *link) -{ - l2cap_cmd_hdr_t cmd; - l2cap_discon_req_cp cp; - l2cap_discon_rsp_cp rp; - struct l2cap_channel *chan; - - m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); - m_adj(m, sizeof(cmd)); - - m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); - m_adj(m, sizeof(cp)); - - cp.scid = letoh16(cp.scid); - cp.dcid = letoh16(cp.dcid); - - chan = l2cap_cid_lookup(cp.dcid); - if (chan == NULL || chan->lc_link != link || chan->lc_rcid != cp.scid) { - l2cap_send_command_rej(link, cmd.ident, L2CAP_REJ_INVALID_CID, - cp.dcid, cp.scid); - return; - } - - rp.dcid = htole16(chan->lc_lcid); - rp.scid = htole16(chan->lc_rcid); - l2cap_send_signal(link, L2CAP_DISCONNECT_RSP, cmd.ident, - sizeof(rp), &rp); - - if (chan->lc_state != L2CAP_CLOSED) - l2cap_close(chan, ECONNRESET); -} - -/* - * Process Received Disconnect Response. We must validate scid and dcid but - * unless we were waiting for this signal, ignore it. - */ -static void -l2cap_recv_disconnect_rsp(struct mbuf *m, struct hci_link *link) -{ - l2cap_cmd_hdr_t cmd; - l2cap_discon_rsp_cp cp; - struct l2cap_req *req; - struct l2cap_channel *chan; - - m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); - m_adj(m, sizeof(cmd)); - - m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); - m_adj(m, sizeof(cp)); - - cp.scid = letoh16(cp.scid); - cp.dcid = letoh16(cp.dcid); - - req = l2cap_request_lookup(link, cmd.ident); - if (req == NULL || req->lr_code != L2CAP_DISCONNECT_REQ) - return; - - chan = req->lr_chan; - if (chan == NULL - || chan->lc_lcid != cp.scid - || chan->lc_rcid != cp.dcid) - return; - - l2cap_request_free(req); - - if (chan->lc_state != L2CAP_WAIT_DISCONNECT) - return; - - l2cap_close(chan, 0); -} - -/* - * Process Received Info Request. We must respond but alas dont - * support anything as yet so thats easy. - */ -static void -l2cap_recv_info_req(struct mbuf *m, struct hci_link *link) -{ - l2cap_cmd_hdr_t cmd; - l2cap_info_req_cp cp; - l2cap_info_rsp_cp rp; - - m_copydata(m, 0, sizeof(cmd), (caddr_t)&cmd); - m_adj(m, sizeof(cmd)); - - m_copydata(m, 0, sizeof(cp), (caddr_t)&cp); - m_adj(m, sizeof(cp)); - - switch(letoh16(cp.type)) { - case L2CAP_CONNLESS_MTU: - case L2CAP_EXTENDED_FEATURES: - default: - rp.type = cp.type; - rp.result = htole16(L2CAP_NOT_SUPPORTED); - - l2cap_send_signal(link, L2CAP_INFO_RSP, cmd.ident, - sizeof(rp), &rp); - break; - } -} - -/* - * Construct signal and wrap in C-Frame for link. - */ -static int -l2cap_send_signal(struct hci_link *link, uint8_t code, uint8_t ident, - uint16_t length, void *data) -{ - struct mbuf *m; - l2cap_hdr_t *hdr; - l2cap_cmd_hdr_t *cmd; - -#ifdef DIAGNOSTIC - if (link == NULL) - return ENETDOWN; - - if (sizeof(l2cap_cmd_hdr_t) + length > link->hl_mtu) - printf("(%s) exceeding L2CAP Signal MTU for link!\n", - device_xname(link->hl_unit->hci_dev)); -#endif - - m = m_gethdr(M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - - hdr = mtod(m, l2cap_hdr_t *); - cmd = (l2cap_cmd_hdr_t *)(hdr + 1); - - m->m_len = m->m_pkthdr.len = MHLEN; - - /* Command Data */ - if (length > 0) - m_copyback(m, sizeof(*hdr) + sizeof(*cmd), length, data, - M_NOWAIT); - - /* Command Header */ - cmd->code = code; - cmd->ident = ident; - cmd->length = htole16(length); - length += sizeof(*cmd); - - /* C-Frame Header */ - hdr->length = htole16(length); - hdr->dcid = htole16(L2CAP_SIGNAL_CID); - length += sizeof(*hdr); - - if (m->m_pkthdr.len != MAX(MHLEN, length)) { - m_freem(m); - return ENOMEM; - } - - m->m_pkthdr.len = length; - m->m_len = MIN(length, MHLEN); - - DPRINTFN(2, "(%s) code %d, ident %d, len %d\n", - device_xname(link->hl_unit->hci_dev), code, ident, length); - - return hci_acl_send(m, link, NULL); -} - -/* - * Send Command Reject packet. - */ -static int -l2cap_send_command_rej(struct hci_link *link, uint8_t ident, - uint32_t reason, ...) -{ - l2cap_cmd_rej_cp cp; - int len = 0; - va_list ap; - - va_start(ap, reason); - - cp.reason = htole16(reason); - - switch (reason) { - case L2CAP_REJ_NOT_UNDERSTOOD: - len = 2; - break; - - case L2CAP_REJ_MTU_EXCEEDED: - len = 4; - cp.data[0] = va_arg(ap, int); /* SigMTU */ - cp.data[0] = htole16(cp.data[0]); - break; - - case L2CAP_REJ_INVALID_CID: - len = 6; - cp.data[0] = va_arg(ap, int); /* dcid */ - cp.data[0] = htole16(cp.data[0]); - cp.data[1] = va_arg(ap, int); /* scid */ - cp.data[1] = htole16(cp.data[1]); - break; - - default: - UNKNOWN(reason); - return EINVAL; - } - - va_end(ap); - - return l2cap_send_signal(link, L2CAP_COMMAND_REJ, ident, len, &cp); -} - -/* - * Send Connect Request - */ -int -l2cap_send_connect_req(struct l2cap_channel *chan) -{ - l2cap_con_req_cp cp; - int err; - - err = l2cap_request_alloc(chan, L2CAP_CONNECT_REQ); - if (err) - return err; - - cp.psm = htole16(chan->lc_raddr.bt_psm); - cp.scid = htole16(chan->lc_lcid); - - return l2cap_send_signal(chan->lc_link, L2CAP_CONNECT_REQ, - chan->lc_link->hl_lastid, sizeof(cp), &cp); -} - -/* - * Send Config Request - * - * For outgoing config request, we only put options in the packet if they - * differ from the default and would have to be actioned. We dont support - * enough option types to make overflowing SigMTU an issue so it can all - * go in one packet. - */ -int -l2cap_send_config_req(struct l2cap_channel *chan) -{ - l2cap_cfg_req_cp *cp; - l2cap_cfg_opt_t *opt; - l2cap_cfg_opt_val_t *val; - uint8_t *next, buf[L2CAP_MTU_MINIMUM]; - int err; - - err = l2cap_request_alloc(chan, L2CAP_CONFIG_REQ); - if (err) - return err; - - /* Config Header (4 octets) */ - cp = (l2cap_cfg_req_cp *)buf; - cp->dcid = htole16(chan->lc_rcid); - cp->flags = 0; /* "No Continuation" */ - - next = buf + sizeof(l2cap_cfg_req_cp); - - /* Incoming MTU (4 octets) */ - if (chan->lc_imtu != L2CAP_MTU_DEFAULT) { - opt = (l2cap_cfg_opt_t *)next; - opt->type = L2CAP_OPT_MTU; - opt->length = L2CAP_OPT_MTU_SIZE; - - val = (l2cap_cfg_opt_val_t *)(opt + 1); - val->mtu = htole16(chan->lc_imtu); - - next += sizeof(l2cap_cfg_opt_t) + L2CAP_OPT_MTU_SIZE; - } - - /* Flush Timeout (4 octets) */ - if (chan->lc_flush != L2CAP_FLUSH_TIMO_DEFAULT) { - opt = (l2cap_cfg_opt_t *)next; - opt->type = L2CAP_OPT_FLUSH_TIMO; - opt->length = L2CAP_OPT_FLUSH_TIMO_SIZE; - - val = (l2cap_cfg_opt_val_t *)(opt + 1); - val->flush_timo = htole16(chan->lc_flush); - - next += sizeof(l2cap_cfg_opt_t) + L2CAP_OPT_FLUSH_TIMO_SIZE; - } - - /* Outgoing QoS Flow (24 octets) */ - /* Retransmission & Flow Control (11 octets) */ - /* - * From here we need to start paying attention to SigMTU as we have - * possibly overflowed the minimum supported.. - */ - - return l2cap_send_signal(chan->lc_link, L2CAP_CONFIG_REQ, - chan->lc_link->hl_lastid, (int)(next - buf), buf); -} - -/* - * Send Disconnect Request - */ -int -l2cap_send_disconnect_req(struct l2cap_channel *chan) -{ - l2cap_discon_req_cp cp; - int err; - - err = l2cap_request_alloc(chan, L2CAP_DISCONNECT_REQ); - if (err) - return err; - - cp.dcid = htole16(chan->lc_rcid); - cp.scid = htole16(chan->lc_lcid); - - return l2cap_send_signal(chan->lc_link, L2CAP_DISCONNECT_REQ, - chan->lc_link->hl_lastid, sizeof(cp), &cp); -} - -/* - * Send Connect Response - */ -int -l2cap_send_connect_rsp(struct hci_link *link, uint8_t ident, uint16_t dcid, - uint16_t scid, uint16_t result) -{ - l2cap_con_rsp_cp cp; - - memset(&cp, 0, sizeof(cp)); - cp.dcid = htole16(dcid); - cp.scid = htole16(scid); - cp.result = htole16(result); - - return l2cap_send_signal(link, L2CAP_CONNECT_RSP, ident, sizeof(cp), &cp); -} diff --git a/sys/netbt/l2cap_socket.c b/sys/netbt/l2cap_socket.c deleted file mode 100644 index 5a584f59598..00000000000 --- a/sys/netbt/l2cap_socket.c +++ /dev/null @@ -1,405 +0,0 @@ -/* $OpenBSD: l2cap_socket.c,v 1.5 2012/12/05 23:20:23 deraadt Exp $ */ -/* $NetBSD: l2cap_socket.c,v 1.9 2008/08/06 15:01:24 plunky Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* load symbolic names */ -#ifdef BLUETOOTH_DEBUG -#define PRUREQUESTS -#define PRCOREQUESTS -#endif - -#include <sys/param.h> -#include <sys/domain.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> /* XXX for EPASSTHROUGH */ -#include <netbt/l2cap.h> - -/* - * L2CAP Sockets - * - * SOCK_SEQPACKET - normal L2CAP connection - * - * SOCK_DGRAM - connectionless L2CAP - XXX not yet - */ - -static void l2cap_connecting(void *); -static void l2cap_connected(void *); -static void l2cap_disconnected(void *, int); -static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); -static void l2cap_complete(void *, int); -static void l2cap_linkmode(void *, int); -static void l2cap_input(void *, struct mbuf *); - -static const struct btproto l2cap_proto = { - l2cap_connecting, - l2cap_connected, - l2cap_disconnected, - l2cap_newconn, - l2cap_complete, - l2cap_linkmode, - l2cap_input, -}; - -/* sysctl variables */ -int l2cap_sendspace = 4096; -int l2cap_recvspace = 4096; - -/* - * User Request. - * up is socket - * m is either - * optional mbuf chain containing message - * ioctl command (PRU_CONTROL) - * nam is either - * optional mbuf chain containing an address - * ioctl data (PRU_CONTROL) - * optionally protocol number (PRU_ATTACH) - * message flags (PRU_RCVD) - * ctl is either - * optional mbuf chain containing socket options - * optional interface pointer (PRU_CONTROL, PRU_PURGEIF) - * l is pointer to process requesting action (if any) - * - * we are responsible for disposing of m and ctl if - * they are mbuf chains - */ -int -l2cap_usrreq(struct socket *up, int req, struct mbuf *m, - struct mbuf *nam, struct mbuf *ctl, struct proc *p) -{ - struct l2cap_channel *pcb = up->so_pcb; - struct sockaddr_bt *sa; - struct mbuf *m0; - int err = 0; - -#ifdef notyet /* XXX */ - DPRINTFN(2, "%s\n", prurequests[req]); -#endif - - switch (req) { - case PRU_CONTROL: - return EPASSTHROUGH; - -#ifdef notyet /* XXX */ - case PRU_PURGEIF: - return EOPNOTSUPP; -#endif - - case PRU_ATTACH: - /* XXX solock() and bt_lock fiddling in NetBSD */ - if (pcb != NULL) - return EINVAL; - /* - * For L2CAP socket PCB we just use an l2cap_channel structure - * since we have nothing to add.. - */ - err = soreserve(up, l2cap_sendspace, l2cap_recvspace); - if (err) - return err; - - return l2cap_attach((struct l2cap_channel **)&up->so_pcb, - &l2cap_proto, up); - } - - if (pcb == NULL) { - err = EINVAL; - goto release; - } - - switch(req) { - case PRU_DISCONNECT: - soisdisconnecting(up); - return l2cap_disconnect(pcb, up->so_linger); - - case PRU_ABORT: - l2cap_disconnect(pcb, 0); - soisdisconnected(up); - /* fall through to */ - case PRU_DETACH: - return l2cap_detach((struct l2cap_channel **)&up->so_pcb); - - case PRU_BIND: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - - if (sa->bt_len != sizeof(struct sockaddr_bt)) - return EINVAL; - - if (sa->bt_family != AF_BLUETOOTH) - return EAFNOSUPPORT; - - return l2cap_bind(pcb, sa); - - case PRU_CONNECT: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - - if (sa->bt_len != sizeof(struct sockaddr_bt)) - return EINVAL; - - if (sa->bt_family != AF_BLUETOOTH) - return EAFNOSUPPORT; - - soisconnecting(up); - return l2cap_connect(pcb, sa); - - case PRU_PEERADDR: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - nam->m_len = sizeof(struct sockaddr_bt); - return l2cap_peeraddr(pcb, sa); - - case PRU_SOCKADDR: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - nam->m_len = sizeof(struct sockaddr_bt); - return l2cap_sockaddr(pcb, sa); - - case PRU_SHUTDOWN: - socantsendmore(up); - break; - - case PRU_SEND: - KASSERT(m != NULL); - if (m->m_pkthdr.len == 0) - break; - - if (m->m_pkthdr.len > pcb->lc_omtu) { - err = EMSGSIZE; - break; - } - - m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if (m0 == NULL) { - err = ENOMEM; - break; - } - - if (ctl) /* no use for that */ - m_freem(ctl); - - sbappendrecord(&up->so_snd, m); - return l2cap_send(pcb, m0); - - case PRU_SENSE: - return 0; /* (no release) */ - - case PRU_RCVD: - case PRU_RCVOOB: - return EOPNOTSUPP; /* (no release) */ - - case PRU_LISTEN: - return l2cap_listen(pcb); - - case PRU_ACCEPT: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - nam->m_len = sizeof(struct sockaddr_bt); - return l2cap_peeraddr(pcb, sa); - - case PRU_CONNECT2: - case PRU_SENDOOB: - case PRU_FASTTIMO: - case PRU_SLOWTIMO: - case PRU_PROTORCV: - case PRU_PROTOSEND: - err = EOPNOTSUPP; - break; - - default: - UNKNOWN(req); - err = EOPNOTSUPP; - break; - } - -release: - if (m) m_freem(m); - if (ctl) m_freem(ctl); - return err; -} - -/* - * l2cap_ctloutput(request, socket, level, optname, opt) - * - * Apply configuration commands to channel. This corresponds to - * "Reconfigure Channel Request" in the L2CAP specification. - */ -int -l2cap_ctloutput(int req, struct socket *so, int level, - int optname, struct mbuf **opt) -{ - struct l2cap_channel *pcb = so->so_pcb; - struct mbuf *m; - int err = 0; - -#ifdef notyet /* XXX */ - DPRINTFN(2, "%s\n", prcorequests[req]); -#endif - - if (pcb == NULL) - return EINVAL; - - if (level != BTPROTO_L2CAP) { - err = EINVAL; - if (req == PRCO_SETOPT && *opt) - m_free(*opt); - } else switch(req) { - case PRCO_GETOPT: - m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = l2cap_getopt(pcb, optname, mtod(m, void *)); - if (m->m_len == 0) { - m_freem(m); - m = NULL; - err = ENOPROTOOPT; - } - *opt = m; - break; - - case PRCO_SETOPT: - m = *opt; - err = l2cap_setopt(pcb, optname, m); - m_freem(m); - break; - - default: - err = ENOPROTOOPT; - break; - } - - return err; -} - -/********************************************************************** - * - * L2CAP Protocol socket callbacks - * - */ - -static void -l2cap_connecting(void *arg) -{ - struct socket *so = arg; - - DPRINTF("Connecting\n"); - soisconnecting(so); -} - -static void -l2cap_connected(void *arg) -{ - struct socket *so = arg; - - DPRINTF("Connected\n"); - soisconnected(so); -} - -static void -l2cap_disconnected(void *arg, int err) -{ - struct socket *so = arg; - - DPRINTF("Disconnected (%d)\n", err); - - so->so_error = err; - soisdisconnected(so); -} - -static void * -l2cap_newconn(void *arg, struct sockaddr_bt *laddr, - struct sockaddr_bt *raddr) -{ - struct socket *so = arg; - - DPRINTF("New Connection\n"); - so = sonewconn(so, 0); - if (so == NULL) - return NULL; - - soisconnecting(so); - - return so->so_pcb; -} - -static void -l2cap_complete(void *arg, int count) -{ - struct socket *so = arg; - - while (count-- > 0) - sbdroprecord(&so->so_snd); - - sowwakeup(so); -} - -static void -l2cap_linkmode(void *arg, int new) -{ - struct socket *so = arg; - int mode; - - DPRINTF("auth %s, encrypt %s, secure %s\n", - (new & L2CAP_LM_AUTH ? "on" : "off"), - (new & L2CAP_LM_ENCRYPT ? "on" : "off"), - (new & L2CAP_LM_SECURE ? "on" : "off")); - - (void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode); - if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH)) - || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT)) - || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE))) - l2cap_disconnect(so->so_pcb, 0); -} - -static void -l2cap_input(void *arg, struct mbuf *m) -{ - struct socket *so = arg; - - if (m->m_pkthdr.len > sbspace(&so->so_rcv)) { - printf("%s: packet (%d bytes) dropped (socket buffer full)\n", - __func__, m->m_pkthdr.len); - m_freem(m); - return; - } - - DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); - - sbappendrecord(&so->so_rcv, m); - sorwakeup(so); -} diff --git a/sys/netbt/l2cap_upper.c b/sys/netbt/l2cap_upper.c deleted file mode 100644 index bcefcf54719..00000000000 --- a/sys/netbt/l2cap_upper.c +++ /dev/null @@ -1,517 +0,0 @@ -/* $OpenBSD: l2cap_upper.c,v 1.6 2013/01/06 22:06:54 martynas Exp $ */ -/* $NetBSD: l2cap_upper.c,v 1.9 2008/08/06 15:01:24 plunky Exp $ */ - -/*- - * Copyright (c) 2005 Iain Hibbert. - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> - -/******************************************************************************* - * - * L2CAP Channel - Upper Protocol API - */ - -/* - * l2cap_attach(handle, btproto, upper) - * - * attach new l2cap_channel to handle, populate - * with reasonable defaults - */ -int -l2cap_attach(struct l2cap_channel **handle, - const struct btproto *proto, void *upper) -{ - struct l2cap_channel *chan; - - KASSERT(handle != NULL); - KASSERT(proto != NULL); - KASSERT(upper != NULL); - - chan = malloc(sizeof(*chan), M_BLUETOOTH, M_NOWAIT | M_ZERO); - if (chan == NULL) - return ENOMEM; - - chan->lc_proto = proto; - chan->lc_upper = upper; - - chan->lc_state = L2CAP_CLOSED; - - chan->lc_lcid = L2CAP_NULL_CID; - chan->lc_rcid = L2CAP_NULL_CID; - - chan->lc_laddr.bt_len = sizeof(struct sockaddr_bt); - chan->lc_laddr.bt_family = AF_BLUETOOTH; - chan->lc_laddr.bt_psm = L2CAP_PSM_ANY; - - chan->lc_raddr.bt_len = sizeof(struct sockaddr_bt); - chan->lc_raddr.bt_family = AF_BLUETOOTH; - chan->lc_raddr.bt_psm = L2CAP_PSM_ANY; - - chan->lc_imtu = L2CAP_MTU_DEFAULT; - chan->lc_omtu = L2CAP_MTU_DEFAULT; - chan->lc_flush = L2CAP_FLUSH_TIMO_DEFAULT; - - memcpy(&chan->lc_iqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); - memcpy(&chan->lc_oqos, &l2cap_default_qos, sizeof(l2cap_qos_t)); - - *handle = chan; - return 0; -} - -/* - * l2cap_bind(l2cap_channel, sockaddr) - * - * set local address of channel - */ -int -l2cap_bind(struct l2cap_channel *chan, struct sockaddr_bt *addr) -{ - - memcpy(&chan->lc_laddr, addr, sizeof(struct sockaddr_bt)); - return 0; -} - -/* - * l2cap_sockaddr(l2cap_channel, sockaddr) - * - * get local address of channel - */ -int -l2cap_sockaddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) -{ - - memcpy(addr, &chan->lc_laddr, sizeof(struct sockaddr_bt)); - return 0; -} - -/* - * l2cap_connect(l2cap_channel, sockaddr) - * - * Initiate a connection to destination. This corresponds to - * "Open Channel Request" in the L2CAP specification and will - * result in one of the following: - * - * proto->connected(upper) - * proto->disconnected(upper, error) - * - * and, optionally - * proto->connecting(upper) - */ -int -l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest) -{ - struct hci_unit *unit; - int err; - - memcpy(&chan->lc_raddr, dest, sizeof(struct sockaddr_bt)); - - if (L2CAP_PSM_INVALID(chan->lc_raddr.bt_psm)) - return EINVAL; - - if (bdaddr_any(&chan->lc_raddr.bt_bdaddr)) - return EDESTADDRREQ; - - /* set local address if it needs setting */ - if (bdaddr_any(&chan->lc_laddr.bt_bdaddr)) { - err = hci_route_lookup(&chan->lc_laddr.bt_bdaddr, - &chan->lc_raddr.bt_bdaddr); - if (err) - return err; - } - - unit = hci_unit_lookup(&chan->lc_laddr.bt_bdaddr); - if (unit == NULL) - return EHOSTUNREACH; - - /* attach to active list */ - err = l2cap_cid_alloc(chan); - if (err) - return err; - - /* open link to remote device */ - chan->lc_link = hci_acl_open(unit, &chan->lc_raddr.bt_bdaddr); - if (chan->lc_link == NULL) - return EHOSTUNREACH; - - /* set the link mode */ - err = l2cap_setmode(chan); - if (err == EINPROGRESS) { - chan->lc_state = L2CAP_WAIT_SEND_CONNECT_REQ; - (*chan->lc_proto->connecting)(chan->lc_upper); - return 0; - } - if (err) - goto fail; - - /* - * We can queue a connect request now even though the link may - * not yet be open; Our mode setting is assured, and the queue - * will be started automatically at the right time. - */ - chan->lc_state = L2CAP_WAIT_RECV_CONNECT_RSP; - err = l2cap_send_connect_req(chan); - if (err) - goto fail; - - return 0; - -fail: - chan->lc_state = L2CAP_CLOSED; - hci_acl_close(chan->lc_link, err); - chan->lc_link = NULL; - return err; -} - -/* - * l2cap_peeraddr(l2cap_channel, sockaddr) - * - * get remote address of channel - */ -int -l2cap_peeraddr(struct l2cap_channel *chan, struct sockaddr_bt *addr) -{ - - memcpy(addr, &chan->lc_raddr, sizeof(struct sockaddr_bt)); - return 0; -} - -/* - * l2cap_disconnect(l2cap_channel, linger) - * - * Initiate L2CAP disconnection. This corresponds to - * "Close Channel Request" in the L2CAP specification - * and will result in a call to - * - * proto->disconnected(upper, error) - * - * when the disconnection is complete. If linger is set, - * the call will not be made until data has flushed from - * the queue. - */ -int -l2cap_disconnect(struct l2cap_channel *chan, int linger) -{ - int err = 0; - - if (chan->lc_state == L2CAP_CLOSED - || chan->lc_state == L2CAP_WAIT_DISCONNECT) - return EINVAL; - - chan->lc_flags |= L2CAP_SHUTDOWN; - - /* - * no need to do anything unless the queue is empty or - * we are not lingering.. - */ - if ((IF_IS_EMPTY(&chan->lc_txq) && chan->lc_pending == 0) - || linger == 0) { - chan->lc_state = L2CAP_WAIT_DISCONNECT; - err = l2cap_send_disconnect_req(chan); - if (err) - l2cap_close(chan, err); - } - return err; -} - -/* - * l2cap_detach(handle) - * - * Detach l2cap channel from handle & close it down - */ -int -l2cap_detach(struct l2cap_channel **handle) -{ - struct l2cap_channel *chan; - - chan = *handle; - *handle = NULL; - - if (chan->lc_state != L2CAP_CLOSED) - l2cap_close(chan, 0); - - if (chan->lc_lcid != L2CAP_NULL_CID) { - LIST_REMOVE(chan, lc_ncid); - chan->lc_lcid = L2CAP_NULL_CID; - } - - IF_PURGE(&chan->lc_txq); - - /* - * Could implement some kind of delayed expunge to make sure that the - * CID is really dead before it becomes available for reuse? - */ - - free(chan, M_BLUETOOTH); - return 0; -} - -/* - * l2cap_listen(l2cap_channel) - * - * Use this channel as a listening post (until detached). This will - * result in calls to: - * - * proto->newconn(upper, laddr, raddr) - * - * for incoming connections matching the psm and local address of the - * channel (NULL psm/address are permitted and match any protocol/device). - * - * The upper layer should create and return a new channel. - * - * You cannot use this channel for anything else subsequent to this call - */ -int -l2cap_listen(struct l2cap_channel *chan) -{ - struct l2cap_channel *used, *prev = NULL; - - if (chan->lc_lcid != L2CAP_NULL_CID) - return EINVAL; - - if (chan->lc_laddr.bt_psm != L2CAP_PSM_ANY - && L2CAP_PSM_INVALID(chan->lc_laddr.bt_psm)) - return EADDRNOTAVAIL; - - /* - * This CID is irrelevant, as the channel is not stored on the active - * list and the socket code does not allow operations on listening - * sockets, but we set it so the detach code knows to LIST_REMOVE the - * channel. - */ - chan->lc_lcid = L2CAP_SIGNAL_CID; - - /* - * The list of listening channels is stored in an order such that new - * listeners dont usurp current listeners, but that specific listening - * takes precedence over promiscuous, and the connect request code can - * easily use the first matching entry. - */ - LIST_FOREACH(used, &l2cap_listen_list, lc_ncid) { - if (used->lc_laddr.bt_psm < chan->lc_laddr.bt_psm) - break; - - if (used->lc_laddr.bt_psm == chan->lc_laddr.bt_psm - && bdaddr_any(&used->lc_laddr.bt_bdaddr) - && !bdaddr_any(&chan->lc_laddr.bt_bdaddr)) - break; - - prev = used; - } - - if (prev == NULL) - LIST_INSERT_HEAD(&l2cap_listen_list, chan, lc_ncid); - else - LIST_INSERT_AFTER(prev, chan, lc_ncid); - - return 0; -} - -/* - * l2cap_send(l2cap_channel, mbuf) - * - * Output SDU on channel described by channel. This corresponds - * to "Send Data Request" in the L2CAP specification. The upper - * layer will be notified when SDU's have completed sending by a - * call to: - * - * proto->complete(upper, n) - * - * (currently n == 1) - * - * Note: I'm not sure how this will work out, but I think that - * if outgoing Retransmission Mode or Flow Control Mode is - * negotiated then this call will not be made until the SDU has - * been acknowledged by the peer L2CAP entity. For 'Best Effort' - * it will be made when the packet has cleared the controller - * buffers. - * - * We only support Basic mode so far, so encapsulate with a - * B-Frame header and start sending if we are not already - */ -int -l2cap_send(struct l2cap_channel *chan, struct mbuf *m) -{ - l2cap_hdr_t *hdr; - int plen; - - if (chan->lc_state == L2CAP_CLOSED) { - m_freem(m); - return ENOTCONN; - } - - plen = m->m_pkthdr.len; - - DPRINTFN(5, "send %d bytes on CID #%d (pending = %d)\n", - plen, chan->lc_lcid, chan->lc_pending); - - /* Encapsulate with B-Frame */ - M_PREPEND(m, sizeof(l2cap_hdr_t), M_DONTWAIT); - if (m == NULL) - return ENOMEM; - - hdr = mtod(m, l2cap_hdr_t *); - hdr->length = htole16(plen); - hdr->dcid = htole16(chan->lc_rcid); - - /* Queue it on our list */ - IF_ENQUEUE(&chan->lc_txq, m); - - /* If we are not sending, then start doing so */ - if (chan->lc_pending == 0) - return l2cap_start(chan); - - return 0; -} - -int -l2cap_setlinkmode(struct l2cap_channel *chan, int mode) -{ - int err = 0; - - mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH); - - if (mode & L2CAP_LM_SECURE) - mode |= L2CAP_LM_ENCRYPT; - - if (mode & L2CAP_LM_ENCRYPT) - mode |= L2CAP_LM_AUTH; - - chan->lc_mode = mode; - - if (chan->lc_state == L2CAP_OPEN) - err = l2cap_setmode(chan); - return (err); -} - -/* - * l2cap_setopt(l2cap_channel, opt, addr) - * - * Apply configuration options to channel. This corresponds to - * "Configure Channel Request" in the L2CAP specification. - * - * for SO_L2CAP_LM, the settings will take effect when the - * channel is established. If the channel is already open, - * a call to - * proto->linkmode(upper, new) - * - * will be made when the change is complete. - */ -int -l2cap_setopt(struct l2cap_channel *chan, int opt, struct mbuf *m) -{ - int err = 0; - uint16_t mtu; - - switch (opt) { - case SO_L2CAP_IMTU: /* set Incoming MTU */ - if (m == NULL || m->m_len != sizeof(uint16_t)) - err = EINVAL; - else { - mtu = *mtod(m, uint16_t *); - if (mtu < L2CAP_MTU_MINIMUM) - err = EINVAL; - else if (chan->lc_state == L2CAP_CLOSED) - chan->lc_imtu = mtu; - else - err = EBUSY; - } - - break; - - case SO_L2CAP_LM: /* set link mode */ - if (m == NULL || m->m_len != sizeof(int)) - err = EINVAL; - else { - err = l2cap_setlinkmode(chan, *mtod(m, int *)); - } - - break; - - case SO_L2CAP_OQOS: /* set Outgoing QoS flow spec */ - case SO_L2CAP_FLUSH: /* set Outgoing Flush Timeout */ - default: - err = ENOPROTOOPT; - break; - } - - return err; -} - -/* - * l2cap_getopt(l2cap_channel, opt, addr) - * - * Return configuration parameters. - */ -int -l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr) -{ - - switch (opt) { - case SO_L2CAP_IMTU: /* get Incoming MTU */ - *(uint16_t *)addr = chan->lc_imtu; - return sizeof(uint16_t); - - case SO_L2CAP_OMTU: /* get Outgoing MTU */ - *(uint16_t *)addr = chan->lc_omtu; - return sizeof(uint16_t); - - case SO_L2CAP_IQOS: /* get Incoming QoS flow spec */ - memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t)); - return sizeof(l2cap_qos_t); - - case SO_L2CAP_OQOS: /* get Outgoing QoS flow spec */ - memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t)); - return sizeof(l2cap_qos_t); - - case SO_L2CAP_FLUSH: /* get Flush Timeout */ - *(uint16_t *)addr = chan->lc_flush; - return sizeof(uint16_t); - - case SO_L2CAP_LM: /* get link mode */ - *(int *)addr = chan->lc_mode; - return sizeof(int); - - default: - break; - } - - return 0; -} diff --git a/sys/netbt/rfcomm.h b/sys/netbt/rfcomm.h deleted file mode 100644 index ba7149e3ef3..00000000000 --- a/sys/netbt/rfcomm.h +++ /dev/null @@ -1,427 +0,0 @@ -/* $OpenBSD: rfcomm.h,v 1.5 2009/11/21 13:05:32 guenther Exp $ */ -/* $NetBSD: rfcomm.h,v 1.8 2008/09/08 23:36:55 gmcgarry Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/*- - * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: rfcomm.h,v 1.5 2009/11/21 13:05:32 guenther Exp $ - * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h,v 1.4 2005/01/11 01:39:53 emax Exp $ - */ - -#ifndef _NETBT_RFCOMM_H_ -#define _NETBT_RFCOMM_H_ - -#include <sys/types.h> - -/************************************************************************* - ************************************************************************* - ** RFCOMM ** - ************************************************************************* - *************************************************************************/ - -#define RFCOMM_MTU_MAX 32767 -#define RFCOMM_MTU_MIN 23 -#define RFCOMM_MTU_DEFAULT 127 - -#define RFCOMM_CREDITS_MAX 255 /* in any single packet */ -#define RFCOMM_CREDITS_DEFAULT 7 /* default initial value */ - -#define RFCOMM_CHANNEL_ANY 0 -#define RFCOMM_CHANNEL_MIN 1 -#define RFCOMM_CHANNEL_MAX 30 - -/* RFCOMM frame types */ -#define RFCOMM_FRAME_SABM 0x2f -#define RFCOMM_FRAME_DISC 0x43 -#define RFCOMM_FRAME_UA 0x63 -#define RFCOMM_FRAME_DM 0x0f -#define RFCOMM_FRAME_UIH 0xef - -/* RFCOMM MCC commands */ -#define RFCOMM_MCC_TEST 0x08 /* Test */ -#define RFCOMM_MCC_FCON 0x28 /* Flow Control on */ -#define RFCOMM_MCC_FCOFF 0x18 /* Flow Control off */ -#define RFCOMM_MCC_MSC 0x38 /* Modem Status Command */ -#define RFCOMM_MCC_RPN 0x24 /* Remote Port Negotiation */ -#define RFCOMM_MCC_RLS 0x14 /* Remote Line Status */ -#define RFCOMM_MCC_PN 0x20 /* Port Negotiation */ -#define RFCOMM_MCC_NSC 0x04 /* Non Supported Command */ - -/* RFCOMM modem signals */ -#define RFCOMM_MSC_FC 0x02 /* Flow Control asserted */ -#define RFCOMM_MSC_RTC 0x04 /* Ready To Communicate */ -#define RFCOMM_MSC_RTR 0x08 /* Ready To Receive */ -#define RFCOMM_MSC_IC 0x40 /* Incomming Call (RING) */ -#define RFCOMM_MSC_DV 0x80 /* Data Valid */ - -/* RPN parameters - baud rate */ -#define RFCOMM_RPN_BR_2400 0x0 -#define RFCOMM_RPN_BR_4800 0x1 -#define RFCOMM_RPN_BR_7200 0x2 -#define RFCOMM_RPN_BR_9600 0x3 -#define RFCOMM_RPN_BR_19200 0x4 -#define RFCOMM_RPN_BR_38400 0x5 -#define RFCOMM_RPN_BR_57600 0x6 -#define RFCOMM_RPN_BR_115200 0x7 -#define RFCOMM_RPN_BR_230400 0x8 - -/* RPN parameters - data bits */ -#define RFCOMM_RPN_DATA_5 0x0 -#define RFCOMM_RPN_DATA_6 0x1 -#define RFCOMM_RPN_DATA_7 0x2 -#define RFCOMM_RPN_DATA_8 0x3 - -/* RPN parameters - stop bit */ -#define RFCOMM_RPN_STOP_1 0 -#define RFCOMM_RPN_STOP_15 1 - -/* RPN parameters - parity enable */ -#define RFCOMM_RPN_PARITY_NONE 0x0 - -/* RPN parameters - parity type */ -#define RFCOMM_RPN_PARITY_ODD 0x0 -#define RFCOMM_RPN_PARITY_EVEN 0x1 -#define RFCOMM_RPN_PARITY_MARK 0x2 -#define RFCOMM_RPN_PARITY_SPACE 0x3 - -/* RPN parameters - default line_setting */ -#define RFCOMM_RPN_8_N_1 0x03 - -/* RPN parameters - flow control */ -#define RFCOMM_RPN_XON_CHAR 0x11 -#define RFCOMM_RPN_XOFF_CHAR 0x13 -#define RFCOMM_RPN_FLOW_NONE 0x00 - -/* RPN parameters - mask */ -#define RFCOMM_RPN_PM_RATE 0x0001 -#define RFCOMM_RPN_PM_DATA 0x0002 -#define RFCOMM_RPN_PM_STOP 0x0004 -#define RFCOMM_RPN_PM_PARITY 0x0008 -#define RFCOMM_RPN_PM_PTYPE 0x0010 -#define RFCOMM_RPN_PM_XON 0x0020 -#define RFCOMM_RPN_PM_XOFF 0x0040 - -#define RFCOMM_RPN_PM_FLOW 0x3f00 - -#define RFCOMM_RPN_PM_ALL 0x3f7f - -/* RFCOMM command frame header */ -struct rfcomm_cmd_hdr -{ - uint8_t address; - uint8_t control; - uint8_t length; - uint8_t fcs; -} __packed; - -/* RFCOMM MSC command */ -struct rfcomm_mcc_msc -{ - uint8_t address; - uint8_t modem; - uint8_t brk; -} __packed; - -/* RFCOMM RPN command */ -struct rfcomm_mcc_rpn -{ - uint8_t dlci; - uint8_t bit_rate; - uint8_t line_settings; - uint8_t flow_control; - uint8_t xon_char; - uint8_t xoff_char; - uint16_t param_mask; -} __packed; - -/* RFCOMM RLS command */ -struct rfcomm_mcc_rls -{ - uint8_t address; - uint8_t status; -} __packed; - -/* RFCOMM PN command */ -struct rfcomm_mcc_pn -{ - uint8_t dlci; - uint8_t flow_control; - uint8_t priority; - uint8_t ack_timer; - uint16_t mtu; - uint8_t max_retrans; - uint8_t credits; -} __packed; - -/* RFCOMM frame parsing macros */ -#define RFCOMM_DLCI(b) (((b) & 0xfc) >> 2) -#define RFCOMM_TYPE(b) (((b) & 0xef)) - -#define RFCOMM_EA(b) (((b) & 0x01)) -#define RFCOMM_CR(b) (((b) & 0x02) >> 1) -#define RFCOMM_PF(b) (((b) & 0x10) >> 4) - -#define RFCOMM_CHANNEL(dlci) (((dlci) >> 1) & 0x2f) -#define RFCOMM_DIRECTION(dlci) ((dlci) & 0x1) - -#define RFCOMM_MKADDRESS(cr, dlci) \ - ((((dlci) & 0x3f) << 2) | ((cr) << 1) | 0x01) - -#define RFCOMM_MKCONTROL(type, pf) ((((type) & 0xef) | ((pf) << 4))) -#define RFCOMM_MKDLCI(dir, channel) ((((channel) & 0x1f) << 1) | (dir)) - -/* RFCOMM MCC macros */ -#define RFCOMM_MCC_TYPE(b) (((b) & 0xfc) >> 2) -#define RFCOMM_MCC_LENGTH(b) (((b) & 0xfe) >> 1) -#define RFCOMM_MKMCC_TYPE(cr, type) ((((type) << 2) | ((cr) << 1) | 0x01)) - -/* RPN macros */ -#define RFCOMM_RPN_DATA_BITS(line) ((line) & 0x3) -#define RFCOMM_RPN_STOP_BITS(line) (((line) >> 2) & 0x1) -#define RFCOMM_RPN_PARITY(line) (((line) >> 3) & 0x1) - -/************************************************************************* - ************************************************************************* - ** SOCK_STREAM RFCOMM sockets ** - ************************************************************************* - *************************************************************************/ - -/* Socket options */ -#define SO_RFCOMM_MTU 1 /* mtu */ -#define SO_RFCOMM_FC_INFO 2 /* flow control info (below) */ -#define SO_RFCOMM_LM 3 /* link mode */ - -/* Flow control information */ -struct rfcomm_fc_info { - uint8_t lmodem; /* modem signals (local) */ - uint8_t rmodem; /* modem signals (remote) */ - uint8_t tx_cred; /* TX credits */ - uint8_t rx_cred; /* RX credits */ - uint8_t cfc; /* credit flow control */ - uint8_t reserved; -}; - -/* RFCOMM link mode flags */ -#define RFCOMM_LM_AUTH (1<<0) /* want authentication */ -#define RFCOMM_LM_ENCRYPT (1<<1) /* want encryption */ -#define RFCOMM_LM_SECURE (1<<2) /* want secured link */ - -#ifdef _KERNEL - -/* sysctl variables */ -extern int rfcomm_sendspace; -extern int rfcomm_recvspace; -extern int rfcomm_mtu_default; -extern int rfcomm_ack_timeout; -extern int rfcomm_mcc_timeout; - -/* - * Bluetooth RFCOMM session data - * One L2CAP connection == one RFCOMM session - */ - -/* Credit note */ -struct rfcomm_credit { - struct rfcomm_dlc *rc_dlc; /* owner */ - uint16_t rc_len; /* length */ - SIMPLEQ_ENTRY(rfcomm_credit) rc_next; /* next credit */ -}; - -/* RFCOMM session data (one L2CAP channel) */ -struct rfcomm_session { - struct l2cap_channel *rs_l2cap; /* L2CAP pointer */ - uint16_t rs_flags; /* session flags */ - uint16_t rs_state; /* session state */ - uint16_t rs_mtu; /* default MTU */ - - SIMPLEQ_HEAD(,rfcomm_credit) rs_credits; /* credit notes */ - LIST_HEAD(,rfcomm_dlc) rs_dlcs; /* DLC list */ - - struct timeout rs_timeout; /* timeout */ - - LIST_ENTRY(rfcomm_session) rs_next; /* next session */ -}; - -LIST_HEAD(rfcomm_session_list, rfcomm_session); -extern struct rfcomm_session_list rfcomm_session_active; -extern struct rfcomm_session_list rfcomm_session_listen; - -/* Session state */ -#define RFCOMM_SESSION_CLOSED 0 -#define RFCOMM_SESSION_WAIT_CONNECT 1 -#define RFCOMM_SESSION_OPEN 2 -#define RFCOMM_SESSION_WAIT_DISCONNECT 3 -#define RFCOMM_SESSION_LISTEN 4 - -/* Session flags */ -#define RFCOMM_SESSION_INITIATOR (1 << 0) /* we are initiator */ -#define RFCOMM_SESSION_CFC (1 << 1) /* credit flow control */ -#define RFCOMM_SESSION_LFC (1 << 2) /* local flow control */ -#define RFCOMM_SESSION_RFC (1 << 3) /* remote flow control */ -#define RFCOMM_SESSION_FREE (1 << 4) /* self lock out for free */ - -#define IS_INITIATOR(rs) ((rs)->rs_flags & RFCOMM_SESSION_INITIATOR) - -/* Bluetooth RFCOMM DLC data (connection) */ -struct rfcomm_dlc { - struct rfcomm_session *rd_session; /* RFCOMM session */ - uint8_t rd_dlci; /* RFCOMM DLCI */ - - uint16_t rd_flags; /* DLC flags */ - uint16_t rd_state; /* DLC state */ - uint16_t rd_mtu; /* MTU */ - int rd_mode; /* link mode */ - - struct sockaddr_bt rd_laddr; /* local address */ - struct sockaddr_bt rd_raddr; /* remote address */ - - uint8_t rd_lmodem; /* local modem signls */ - uint8_t rd_rmodem; /* remote modem signals */ - - int rd_rxcred; /* receive credits (sent) */ - size_t rd_rxsize; /* receive buffer (bytes, avail) */ - int rd_txcred; /* transmit credits (unused) */ - int rd_pending; /* packets sent but not complete */ - - struct timeout rd_timeout; /* timeout */ - struct mbuf *rd_txbuf; /* transmit buffer */ - - const struct btproto *rd_proto; /* upper layer callbacks */ - void *rd_upper; /* upper layer argument */ - - LIST_ENTRY(rfcomm_dlc) rd_next; /* next dlc on session */ -}; - -/* - * Credit Flow Control works in the following way. - * - * txcred is how many packets we can send. Received credit - * is added to this value, and it is decremented each time - * we send a packet. - * - * rxsize is the number of bytes that are available in the - * upstream receive buffer. - * - * rxcred is the number of credits that we have previously - * sent that are still unused. This value will be decreased - * for each packet we receive and we will add to it when we - * send credits. We calculate the amount of credits to send - * by the cunning formula "(space / mtu) - sent" so that if - * we get a bunch of small packets, we can continue sending - * credits without risking buffer overflow. - */ - -/* DLC flags */ -#define RFCOMM_DLC_DETACH (1 << 0) /* DLC to be detached */ -#define RFCOMM_DLC_SHUTDOWN (1 << 1) /* DLC to be shutdown */ - -/* DLC state */ -#define RFCOMM_DLC_CLOSED 0 /* no session */ -#define RFCOMM_DLC_WAIT_SESSION 1 /* waiting for session */ -#define RFCOMM_DLC_WAIT_CONNECT 2 /* waiting for connect */ -#define RFCOMM_DLC_WAIT_SEND_SABM 3 /* waiting to send SABM */ -#define RFCOMM_DLC_WAIT_SEND_UA 4 /* waiting to send UA */ -#define RFCOMM_DLC_WAIT_RECV_UA 5 /* waiting to receive UA */ -#define RFCOMM_DLC_OPEN 6 /* can send/receive */ -#define RFCOMM_DLC_WAIT_DISCONNECT 7 /* waiting for disconnect */ -#define RFCOMM_DLC_LISTEN 8 /* listening DLC */ - -/* - * Bluetooth RFCOMM socket kernel prototypes - */ - -struct socket; - -/* rfcomm_dlc.c */ -struct rfcomm_dlc *rfcomm_dlc_lookup(struct rfcomm_session *, int); -struct rfcomm_dlc *rfcomm_dlc_newconn(struct rfcomm_session *, int); -void rfcomm_dlc_close(struct rfcomm_dlc *, int); -void rfcomm_dlc_timeout(void *); -int rfcomm_dlc_setmode(struct rfcomm_dlc *); -int rfcomm_dlc_connect(struct rfcomm_dlc *); -int rfcomm_dlc_open(struct rfcomm_dlc *); -void rfcomm_dlc_start(struct rfcomm_dlc *); - -/* rfcomm_session.c */ -void rfcomm_init(void); -struct rfcomm_session *rfcomm_session_alloc(struct rfcomm_session_list *, struct sockaddr_bt *); -struct rfcomm_session *rfcomm_session_lookup(struct sockaddr_bt *, struct sockaddr_bt *); -void rfcomm_session_free(struct rfcomm_session *); -int rfcomm_session_send_frame(struct rfcomm_session *, int, int); -int rfcomm_session_send_uih(struct rfcomm_session *, struct rfcomm_dlc *, int, struct mbuf *); -int rfcomm_session_send_mcc(struct rfcomm_session *, int, uint8_t, void *, int); - -/* rfcomm_socket.c */ -int rfcomm_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, - struct mbuf *, struct proc *); -int rfcomm_ctloutput(int, struct socket *, int, int, struct mbuf **); - -/* rfcomm_upper.c */ -int rfcomm_attach(struct rfcomm_dlc **, const struct btproto *, void *); -int rfcomm_bind(struct rfcomm_dlc *, struct sockaddr_bt *); -int rfcomm_sockaddr(struct rfcomm_dlc *, struct sockaddr_bt *); -int rfcomm_connect(struct rfcomm_dlc *, struct sockaddr_bt *); -int rfcomm_peeraddr(struct rfcomm_dlc *, struct sockaddr_bt *); -int rfcomm_disconnect(struct rfcomm_dlc *, int); -int rfcomm_detach(struct rfcomm_dlc **); -int rfcomm_listen(struct rfcomm_dlc *); -int rfcomm_send(struct rfcomm_dlc *, struct mbuf *); -int rfcomm_rcvd(struct rfcomm_dlc *, size_t); -int rfcomm_setopt(struct rfcomm_dlc *, int, struct mbuf *); -int rfcomm_getopt(struct rfcomm_dlc *, int, void *); - -#endif /* _KERNEL */ - -#endif /* _NETBT_RFCOMM_H_ */ diff --git a/sys/netbt/rfcomm_dlc.c b/sys/netbt/rfcomm_dlc.c deleted file mode 100644 index 843474c8ca1..00000000000 --- a/sys/netbt/rfcomm_dlc.c +++ /dev/null @@ -1,410 +0,0 @@ -/* $OpenBSD: rfcomm_dlc.c,v 1.5 2009/11/21 13:05:32 guenther Exp $ */ -/* $NetBSD: rfcomm_dlc.c,v 1.6 2008/08/06 15:01:24 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> -#include <netbt/rfcomm.h> - -/* - * rfcomm_dlc_lookup(rfcomm_session, dlci) - * - * Find DLC on session with matching dlci - */ -struct rfcomm_dlc * -rfcomm_dlc_lookup(struct rfcomm_session *rs, int dlci) -{ - struct rfcomm_dlc *dlc; - - LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) { - if (dlc->rd_dlci == dlci) - break; - } - - return dlc; -} - -/* - * rfcomm_dlc_newconn(rfcomm_session, dlci) - * - * handle a new dlc request (since its called from a couple of places) - */ -struct rfcomm_dlc * -rfcomm_dlc_newconn(struct rfcomm_session *rs, int dlci) -{ - struct rfcomm_session *ls; - struct rfcomm_dlc *new, *dlc, *any, *best; - struct sockaddr_bt laddr, raddr, addr; - int chan; - - /* - * Search amongst the listening DLC community for the best match for - * address & channel. We keep listening DLC's hanging on listening - * sessions in a last first order, so scan the entire bunch and keep - * a note of the best address and BDADDR_ANY matches in order to find - * the oldest and most specific match. - */ - l2cap_sockaddr(rs->rs_l2cap, &laddr); - l2cap_peeraddr(rs->rs_l2cap, &raddr); - chan = RFCOMM_CHANNEL(dlci); - new = NULL; - - any = best = NULL; - LIST_FOREACH(ls, &rfcomm_session_listen, rs_next) { - l2cap_sockaddr(ls->rs_l2cap, &addr); - - if (addr.bt_psm != laddr.bt_psm) - continue; - - if (bdaddr_same(&laddr.bt_bdaddr, &addr.bt_bdaddr)) { - LIST_FOREACH(dlc, &ls->rs_dlcs, rd_next) { - if (dlc->rd_laddr.bt_channel == chan) - best = dlc; - } - } - - if (bdaddr_any(&addr.bt_bdaddr)) { - LIST_FOREACH(dlc, &ls->rs_dlcs, rd_next) { - if (dlc->rd_laddr.bt_channel == chan) - any = dlc; - } - } - } - - dlc = best ? best : any; - - /* XXX - * Note that if this fails, we could have missed a chance to open - * a connection - really need to rewrite the strategy for storing - * listening DLC's so all can be checked in turn.. - */ - if (dlc != NULL) - new = (*dlc->rd_proto->newconn)(dlc->rd_upper, &laddr, &raddr); - - if (new == NULL) { - rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci); - return NULL; - } - - new->rd_dlci = dlci; - new->rd_mtu = rfcomm_mtu_default; - new->rd_mode = dlc->rd_mode; - - memcpy(&new->rd_laddr, &laddr, sizeof(struct sockaddr_bt)); - new->rd_laddr.bt_channel = chan; - - memcpy(&new->rd_raddr, &raddr, sizeof(struct sockaddr_bt)); - new->rd_raddr.bt_channel = chan; - - new->rd_session = rs; - new->rd_state = RFCOMM_DLC_WAIT_CONNECT; - LIST_INSERT_HEAD(&rs->rs_dlcs, new, rd_next); - - return new; -} - -/* - * rfcomm_dlc_close(dlc, error) - * - * detach DLC from session and clean up - */ -void -rfcomm_dlc_close(struct rfcomm_dlc *dlc, int err) -{ - struct rfcomm_session *rs; - struct rfcomm_credit *credit; - - KASSERT(dlc->rd_state != RFCOMM_DLC_CLOSED); - - /* Clear credit history */ - rs = dlc->rd_session; - SIMPLEQ_FOREACH(credit, &rs->rs_credits, rc_next) - if (credit->rc_dlc == dlc) - credit->rc_dlc = NULL; - - timeout_del(&dlc->rd_timeout); - - LIST_REMOVE(dlc, rd_next); - dlc->rd_session = NULL; - dlc->rd_state = RFCOMM_DLC_CLOSED; - - (*dlc->rd_proto->disconnected)(dlc->rd_upper, err); - - /* - * It is the responsibility of the party who sends the last - * DISC(dlci) to disconnect the session, but we will schedule - * an expiry just in case that doesnt happen.. - */ - if (LIST_EMPTY(&rs->rs_dlcs)) { - if (rs->rs_state == RFCOMM_SESSION_LISTEN) - rfcomm_session_free(rs); - else - timeout_add_sec(&rs->rs_timeout, rfcomm_ack_timeout); - } -} - -/* - * rfcomm_dlc_timeout(dlc) - * - * DLC timeout function is schedUled when we sent any of SABM, - * DISC, MCC_MSC, or MCC_PN and should be cancelled when we get - * the relevant response. There is nothing to do but shut this - * DLC down. - */ -void -rfcomm_dlc_timeout(void *arg) -{ - struct rfcomm_dlc *dlc = arg; - - mutex_enter(&bt_lock); - - if (dlc->rd_state != RFCOMM_DLC_CLOSED) - rfcomm_dlc_close(dlc, ETIMEDOUT); - else if (dlc->rd_flags & RFCOMM_DLC_DETACH) - free(dlc, M_BLUETOOTH); - - mutex_exit(&bt_lock); -} - -/* - * rfcomm_dlc_setmode(rfcomm_dlc) - * - * Set link mode for DLC. This is only called when the session is - * already open, so we don't need to worry about any previous mode - * settings. - */ -int -rfcomm_dlc_setmode(struct rfcomm_dlc *dlc) -{ - int mode = 0; - - KASSERT(dlc->rd_session != NULL); - KASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN); - - DPRINTF("dlci %d, auth %s, encrypt %s, secure %s\n", dlc->rd_dlci, - (dlc->rd_mode & RFCOMM_LM_AUTH ? "yes" : "no"), - (dlc->rd_mode & RFCOMM_LM_ENCRYPT ? "yes" : "no"), - (dlc->rd_mode & RFCOMM_LM_SECURE ? "yes" : "no")); - - if (dlc->rd_mode & RFCOMM_LM_AUTH) - mode |= L2CAP_LM_AUTH; - - if (dlc->rd_mode & RFCOMM_LM_ENCRYPT) - mode |= L2CAP_LM_ENCRYPT; - - if (dlc->rd_mode & RFCOMM_LM_SECURE) - mode |= L2CAP_LM_SECURE; - - return l2cap_setlinkmode(dlc->rd_session->rs_l2cap, mode); -} - -/* - * rfcomm_dlc_connect(rfcomm_dlc) - * - * initiate DLC connection (session is already connected) - */ -int -rfcomm_dlc_connect(struct rfcomm_dlc *dlc) -{ - struct rfcomm_mcc_pn pn; - int err = 0; - - KASSERT(dlc->rd_session != NULL); - KASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN); - KASSERT(dlc->rd_state == RFCOMM_DLC_WAIT_SESSION); - - /* - * If we have not already sent a PN on the session, we must send - * a PN to negotiate Credit Flow Control, and this setting will - * apply to all future connections for this session. We ask for - * this every time, in order to establish initial credits. - */ - memset(&pn, 0, sizeof(pn)); - pn.dlci = dlc->rd_dlci; - pn.priority = dlc->rd_dlci | 0x07; - pn.mtu = htole16(dlc->rd_mtu); - - pn.flow_control = 0xf0; - dlc->rd_rxcred = (dlc->rd_rxsize / dlc->rd_mtu); - dlc->rd_rxcred = min(dlc->rd_rxcred, RFCOMM_CREDITS_DEFAULT); - pn.credits = dlc->rd_rxcred; - - err = rfcomm_session_send_mcc(dlc->rd_session, 1, - RFCOMM_MCC_PN, &pn, sizeof(pn)); - if (err) - return err; - - dlc->rd_state = RFCOMM_DLC_WAIT_CONNECT; - timeout_add_sec(&dlc->rd_timeout, rfcomm_mcc_timeout); - - return 0; -} - -/* - * rfcomm_dlc_open(rfcomm_dlc) - * - * send "Modem Status Command" and mark DLC as open. - */ -int -rfcomm_dlc_open(struct rfcomm_dlc *dlc) -{ - struct rfcomm_mcc_msc msc; - int err; - - KASSERT(dlc->rd_session != NULL); - KASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN); - - memset(&msc, 0, sizeof(msc)); - msc.address = RFCOMM_MKADDRESS(1, dlc->rd_dlci); - msc.modem = dlc->rd_lmodem & 0xfe; /* EA = 0 */ - msc.brk = 0x00 | 0x01; /* EA = 1 */ - - err = rfcomm_session_send_mcc(dlc->rd_session, 1, - RFCOMM_MCC_MSC, &msc, sizeof(msc)); - if (err) - return err; - - timeout_add_sec(&dlc->rd_timeout, rfcomm_mcc_timeout); - - dlc->rd_state = RFCOMM_DLC_OPEN; - (*dlc->rd_proto->connected)(dlc->rd_upper); - - return 0; -} - -/* - * rfcomm_dlc_start(rfcomm_dlc) - * - * Start sending data (and/or credits) for DLC. Our strategy is to - * send anything we can down to the l2cap layer. When credits run - * out, data will naturally bunch up. When not using credit flow - * control, we limit the number of packets we have pending to reduce - * flow control lag. - * We should deal with channel priority somehow. - */ -void -rfcomm_dlc_start(struct rfcomm_dlc *dlc) -{ - struct rfcomm_session *rs = dlc->rd_session; - struct mbuf *m; - int len, credits; - - KASSERT(rs != NULL); - KASSERT(rs->rs_state == RFCOMM_SESSION_OPEN); - KASSERT(dlc->rd_state == RFCOMM_DLC_OPEN); - - for (;;) { - credits = 0; - len = dlc->rd_mtu; - if (rs->rs_flags & RFCOMM_SESSION_CFC) { - credits = (dlc->rd_rxsize / dlc->rd_mtu); - credits -= dlc->rd_rxcred; - credits = min(credits, RFCOMM_CREDITS_MAX); - - if (credits > 0) - len--; - - if (dlc->rd_txcred == 0) - len = 0; - } else { - if (rs->rs_flags & RFCOMM_SESSION_RFC) - break; - - if (dlc->rd_rmodem & RFCOMM_MSC_FC) - break; - - if (dlc->rd_pending > RFCOMM_CREDITS_DEFAULT) - break; - } - - if (dlc->rd_txbuf == NULL) - len = 0; - - if (len == 0) { - if (credits == 0) - break; - - /* - * No need to send small numbers of credits on their - * own unless the other end hasn't many left. - */ - if (credits < RFCOMM_CREDITS_DEFAULT - && dlc->rd_rxcred > RFCOMM_CREDITS_DEFAULT) - break; - - m = NULL; - } else { - /* - * take what data we can from (front of) txbuf - */ - m = dlc->rd_txbuf; - if (len < m->m_pkthdr.len) { - dlc->rd_txbuf = m_split(m, len, M_DONTWAIT); - if (dlc->rd_txbuf == NULL) { - dlc->rd_txbuf = m; - break; - } - } else { - dlc->rd_txbuf = NULL; - len = m->m_pkthdr.len; - } - } - - DPRINTFN(10, "dlci %d send %d bytes, %d credits, rxcred = %d\n", - dlc->rd_dlci, len, credits, dlc->rd_rxcred); - - if (rfcomm_session_send_uih(rs, dlc, credits, m)) { - printf("%s: lost %d bytes on DLCI %d\n", - __func__, len, dlc->rd_dlci); - - break; - } - - dlc->rd_pending++; - - if (rs->rs_flags & RFCOMM_SESSION_CFC) { - if (len > 0) - dlc->rd_txcred--; - - if (credits > 0) - dlc->rd_rxcred += credits; - } - } -} diff --git a/sys/netbt/rfcomm_session.c b/sys/netbt/rfcomm_session.c deleted file mode 100644 index d3e9e4aa9f9..00000000000 --- a/sys/netbt/rfcomm_session.c +++ /dev/null @@ -1,1686 +0,0 @@ -/* $OpenBSD: rfcomm_session.c,v 1.8 2010/07/29 14:40:47 blambert Exp $ */ -/* $NetBSD: rfcomm_session.c,v 1.14 2008/08/06 15:01:24 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/pool.h> -#include <sys/proc.h> -#include <sys/systm.h> -#include <sys/types.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> -#include <netbt/rfcomm.h> - -/****************************************************************************** - * - * RFCOMM Multiplexer Sessions sit directly on L2CAP channels, and can - * multiplex up to 30 incoming and 30 outgoing connections. - * Only one Multiplexer is allowed between any two devices. - */ - -static void rfcomm_session_timeout(void *); -static void rfcomm_session_recv_sabm(struct rfcomm_session *, int); -static void rfcomm_session_recv_disc(struct rfcomm_session *, int); -static void rfcomm_session_recv_ua(struct rfcomm_session *, int); -static void rfcomm_session_recv_dm(struct rfcomm_session *, int); -static void rfcomm_session_recv_uih(struct rfcomm_session *, int, int, struct mbuf *, int); -static void rfcomm_session_recv_mcc(struct rfcomm_session *, struct mbuf *); -static void rfcomm_session_recv_mcc_test(struct rfcomm_session *, int, struct mbuf *); -static void rfcomm_session_recv_mcc_fcon(struct rfcomm_session *, int); -static void rfcomm_session_recv_mcc_fcoff(struct rfcomm_session *, int); -static void rfcomm_session_recv_mcc_msc(struct rfcomm_session *, int, struct mbuf *); -static void rfcomm_session_recv_mcc_rpn(struct rfcomm_session *, int, struct mbuf *); -static void rfcomm_session_recv_mcc_rls(struct rfcomm_session *, int, struct mbuf *); -static void rfcomm_session_recv_mcc_pn(struct rfcomm_session *, int, struct mbuf *); -static void rfcomm_session_recv_mcc_nsc(struct rfcomm_session *, int, struct mbuf *); - -/* L2CAP callbacks */ -static void rfcomm_session_connecting(void *); -static void rfcomm_session_connected(void *); -static void rfcomm_session_disconnected(void *, int); -static void *rfcomm_session_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); -static void rfcomm_session_complete(void *, int); -static void rfcomm_session_linkmode(void *, int); -static void rfcomm_session_input(void *, struct mbuf *); - -static const struct btproto rfcomm_session_proto = { - rfcomm_session_connecting, - rfcomm_session_connected, - rfcomm_session_disconnected, - rfcomm_session_newconn, - rfcomm_session_complete, - rfcomm_session_linkmode, - rfcomm_session_input, -}; - -struct rfcomm_session_list - rfcomm_session_active = LIST_HEAD_INITIALIZER(rfcomm_session_active); - -struct rfcomm_session_list - rfcomm_session_listen = LIST_HEAD_INITIALIZER(rfcomm_session_listen); - -struct pool rfcomm_credit_pool; - -/* - * RFCOMM System Parameters (see section 5.3) - */ -int rfcomm_mtu_default = 127; /* bytes */ -int rfcomm_ack_timeout = 20; /* seconds */ -int rfcomm_mcc_timeout = 20; /* seconds */ - -/* - * Reversed CRC table as per TS 07.10 Annex B.3.5 - */ -static const uint8_t crctable[256] = { /* reversed, 8-bit, poly=0x07 */ - 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, - 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, - 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, - 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, - - 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, - 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, - 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, - 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, - - 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, - 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, - 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, - 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, - - 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, - 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, - 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, - 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, - - 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, - 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, - 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, - 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, - - 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, - 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, - 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, - 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, - - 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, - 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, - 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, - 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, - - 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, - 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, - 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, - 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf -}; - -#define FCS(f, d) crctable[(f) ^ (d)] - -/* - * rfcomm_init() - * - * initialize the "credit pool". - */ -void -rfcomm_init(void) -{ - pool_init(&rfcomm_credit_pool, 0, 0, 0, 0, "rfcomm_credit", NULL); -} - -/* - * rfcomm_session_alloc(list, sockaddr) - * - * allocate a new session and fill in the blanks, then - * attach session to front of specified list (active or listen) - */ -struct rfcomm_session * -rfcomm_session_alloc(struct rfcomm_session_list *list, - struct sockaddr_bt *laddr) -{ - struct rfcomm_session *rs; - int err; - - rs = malloc(sizeof(*rs), M_BLUETOOTH, M_NOWAIT | M_ZERO); - if (rs == NULL) - return NULL; - - rs->rs_state = RFCOMM_SESSION_CLOSED; - - timeout_set(&rs->rs_timeout, rfcomm_session_timeout, rs); - - SIMPLEQ_INIT(&rs->rs_credits); - LIST_INIT(&rs->rs_dlcs); - - err = l2cap_attach(&rs->rs_l2cap, &rfcomm_session_proto, rs); - if (err) { - free(rs, M_BLUETOOTH); - return NULL; - } - - (void)l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu); - - if (laddr->bt_psm == L2CAP_PSM_ANY) - laddr->bt_psm = L2CAP_PSM_RFCOMM; - - (void)l2cap_bind(rs->rs_l2cap, laddr); - - LIST_INSERT_HEAD(list, rs, rs_next); - - return rs; -} - -/* - * rfcomm_session_free(rfcomm_session) - * - * release a session, including any cleanup - */ -void -rfcomm_session_free(struct rfcomm_session *rs) -{ - struct rfcomm_credit *credit; - - KASSERT(rs != NULL); - KASSERT(LIST_EMPTY(&rs->rs_dlcs)); - - rs->rs_state = RFCOMM_SESSION_CLOSED; - - /* - * If the callout is already invoked we have no way to stop it, - * but it will call us back right away (there are no DLC's) so - * not to worry. - */ - timeout_del(&rs->rs_timeout); - if (timeout_triggered(&rs->rs_timeout)) - return; - - /* - * Take care that rfcomm_session_disconnected() doesnt call - * us back either as it will do if the l2cap_channel has not - * been closed when we detach it.. - */ - if (rs->rs_flags & RFCOMM_SESSION_FREE) - return; - - rs->rs_flags |= RFCOMM_SESSION_FREE; - - /* throw away any remaining credit notes */ - while ((credit = SIMPLEQ_FIRST(&rs->rs_credits)) != NULL) { - SIMPLEQ_REMOVE_HEAD(&rs->rs_credits, rc_next); - pool_put(&rfcomm_credit_pool, credit); - } - - KASSERT(SIMPLEQ_EMPTY(&rs->rs_credits)); - - /* Goodbye! */ - LIST_REMOVE(rs, rs_next); - l2cap_detach(&rs->rs_l2cap); - free(rs, M_BLUETOOTH); -} - -/* - * rfcomm_session_lookup(sockaddr, sockaddr) - * - * Find active rfcomm session matching src and dest addresses - * when src is BDADDR_ANY match any local address - */ -struct rfcomm_session * -rfcomm_session_lookup(struct sockaddr_bt *src, struct sockaddr_bt *dest) -{ - struct rfcomm_session *rs; - struct sockaddr_bt addr; - - LIST_FOREACH(rs, &rfcomm_session_active, rs_next) { - if (rs->rs_state == RFCOMM_SESSION_CLOSED) - continue; - - l2cap_sockaddr(rs->rs_l2cap, &addr); - - if (bdaddr_same(&src->bt_bdaddr, &addr.bt_bdaddr) == 0) - if (bdaddr_any(&src->bt_bdaddr) == 0) - continue; - - l2cap_peeraddr(rs->rs_l2cap, &addr); - - if (addr.bt_psm != dest->bt_psm) - continue; - - if (bdaddr_same(&dest->bt_bdaddr, &addr.bt_bdaddr)) - break; - } - - return rs; -} - -/* - * rfcomm_session_timeout(rfcomm_session) - * - * Session timeouts are scheduled when a session is left or - * created with no DLCs, and when SABM(0) or DISC(0) are - * sent. - * - * So, if it is in an open state with DLC's attached then - * we leave it alone, otherwise the session is lost. - */ -static void -rfcomm_session_timeout(void *arg) -{ - struct rfcomm_session *rs = arg; - struct rfcomm_dlc *dlc; - - KASSERT(rs != NULL); - - mutex_enter(&bt_lock); - - if (rs->rs_state != RFCOMM_SESSION_OPEN) { - DPRINTF("timeout\n"); - rs->rs_state = RFCOMM_SESSION_CLOSED; - - while (!LIST_EMPTY(&rs->rs_dlcs)) { - dlc = LIST_FIRST(&rs->rs_dlcs); - - rfcomm_dlc_close(dlc, ETIMEDOUT); - } - } - - if (LIST_EMPTY(&rs->rs_dlcs)) { - DPRINTF("expiring\n"); - rfcomm_session_free(rs); - } - mutex_exit(&bt_lock); -} - -/*********************************************************************** - * - * RFCOMM Session L2CAP protocol callbacks - * - */ - -static void -rfcomm_session_connecting(void *arg) -{ - /* struct rfcomm_session *rs = arg; */ - - DPRINTF("Connecting\n"); -} - -static void -rfcomm_session_connected(void *arg) -{ - struct rfcomm_session *rs = arg; - - DPRINTF("Connected\n"); - - /* - * L2CAP is open. - * - * If we are initiator, we can send our SABM(0) - * a timeout should be active? - * - * We must take note of the L2CAP MTU because currently - * the L2CAP implementation can only do Basic Mode. - */ - l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu); - - rs->rs_mtu -= 6; /* (RFCOMM overhead could be this big) */ - if (rs->rs_mtu < RFCOMM_MTU_MIN) { - rfcomm_session_disconnected(rs, EINVAL); - return; - } - - if (IS_INITIATOR(rs)) { - int err; - - err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, 0); - if (err) - rfcomm_session_disconnected(rs, err); - - timeout_add_sec(&rs->rs_timeout, rfcomm_ack_timeout); - } -} - -static void -rfcomm_session_disconnected(void *arg, int err) -{ - struct rfcomm_session *rs = arg; - struct rfcomm_dlc *dlc; - - DPRINTF("Disconnected\n"); - - rs->rs_state = RFCOMM_SESSION_CLOSED; - - while (!LIST_EMPTY(&rs->rs_dlcs)) { - dlc = LIST_FIRST(&rs->rs_dlcs); - - rfcomm_dlc_close(dlc, err); - } - - rfcomm_session_free(rs); -} - -static void * -rfcomm_session_newconn(void *arg, struct sockaddr_bt *laddr, - struct sockaddr_bt *raddr) -{ - struct rfcomm_session *new, *rs = arg; - - DPRINTF("New Connection\n"); - - /* - * Incoming session connect request. We should return a new - * session pointer if this is acceptable. The L2CAP layer - * passes local and remote addresses, which we must check as - * only one RFCOMM session is allowed between any two devices - */ - new = rfcomm_session_lookup(laddr, raddr); - if (new != NULL) - return NULL; - - new = rfcomm_session_alloc(&rfcomm_session_active, laddr); - if (new == NULL) - return NULL; - - new->rs_mtu = rs->rs_mtu; - new->rs_state = RFCOMM_SESSION_WAIT_CONNECT; - - /* - * schedule an expiry so that if nothing comes of it we - * can punt. - */ - timeout_add_sec(&new->rs_timeout, rfcomm_mcc_timeout); - - return new->rs_l2cap; -} - -static void -rfcomm_session_complete(void *arg, int count) -{ - struct rfcomm_session *rs = arg; - struct rfcomm_credit *credit; - struct rfcomm_dlc *dlc; - - /* - * count L2CAP packets are 'complete', meaning that they are cleared - * our buffers (for best effort) or arrived safe (for guaranteed) so - * we can take it off our list and pass the message on, so that - * eventually the data can be removed from the sockbuf - */ - while (count-- > 0) { - credit = SIMPLEQ_FIRST(&rs->rs_credits); -#ifdef DIAGNOSTIC - if (credit == NULL) { - printf("%s: too many packets completed!\n", __func__); - break; - } -#endif - dlc = credit->rc_dlc; - if (dlc != NULL) { - dlc->rd_pending--; - (*dlc->rd_proto->complete) - (dlc->rd_upper, credit->rc_len); - - /* - * if not using credit flow control, we may push - * more data now - */ - if ((rs->rs_flags & RFCOMM_SESSION_CFC) == 0 - && dlc->rd_state == RFCOMM_DLC_OPEN) { - rfcomm_dlc_start(dlc); - } - - /* - * When shutdown is indicated, we are just waiting to - * clear outgoing data. - */ - if ((dlc->rd_flags & RFCOMM_DLC_SHUTDOWN) - && dlc->rd_txbuf == NULL && dlc->rd_pending == 0) { - dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT; - rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, - dlc->rd_dlci); - timeout_add_sec(&dlc->rd_timeout, - rfcomm_ack_timeout); - } - } - - SIMPLEQ_REMOVE_HEAD(&rs->rs_credits, rc_next); - pool_put(&rfcomm_credit_pool, credit); - } - - /* - * If session is closed, we are just waiting to clear the queue - */ - if (rs->rs_state == RFCOMM_SESSION_CLOSED) { - if (SIMPLEQ_EMPTY(&rs->rs_credits)) - l2cap_disconnect(rs->rs_l2cap, 0); - } -} - -/* - * Link Mode changed - * - * This is called when a mode change is complete. Proceed with connections - * where appropriate, or pass the new mode to any active DLCs. - */ -static void -rfcomm_session_linkmode(void *arg, int new) -{ - struct rfcomm_session *rs = arg; - struct rfcomm_dlc *dlc, *next; - int err, mode = 0; - - DPRINTF("auth %s, encrypt %s, secure %s\n", - (new & L2CAP_LM_AUTH ? "on" : "off"), - (new & L2CAP_LM_ENCRYPT ? "on" : "off"), - (new & L2CAP_LM_SECURE ? "on" : "off")); - - if (new & L2CAP_LM_AUTH) - mode |= RFCOMM_LM_AUTH; - - if (new & L2CAP_LM_ENCRYPT) - mode |= RFCOMM_LM_ENCRYPT; - - if (new & L2CAP_LM_SECURE) - mode |= RFCOMM_LM_SECURE; - - next = LIST_FIRST(&rs->rs_dlcs); - while ((dlc = next) != NULL) { - next = LIST_NEXT(dlc, rd_next); - - switch (dlc->rd_state) { - case RFCOMM_DLC_WAIT_SEND_SABM: /* we are connecting */ - if ((mode & dlc->rd_mode) != dlc->rd_mode) { - rfcomm_dlc_close(dlc, ECONNABORTED); - } else { - err = rfcomm_session_send_frame(rs, - RFCOMM_FRAME_SABM, dlc->rd_dlci); - if (err) { - rfcomm_dlc_close(dlc, err); - } else { - dlc->rd_state = RFCOMM_DLC_WAIT_RECV_UA; - timeout_add_sec(&dlc->rd_timeout, - rfcomm_ack_timeout); - break; - } - } - - /* - * If we aborted the connection and there are no more DLCs - * on the session, it is our responsibility to disconnect. - */ - if (!LIST_EMPTY(&rs->rs_dlcs)) - break; - - rs->rs_state = RFCOMM_SESSION_WAIT_DISCONNECT; - rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, 0); - timeout_add_sec(&rs->rs_timeout, rfcomm_ack_timeout); - break; - - case RFCOMM_DLC_WAIT_SEND_UA: /* they are connecting */ - if ((mode & dlc->rd_mode) != dlc->rd_mode) { - rfcomm_session_send_frame(rs, - RFCOMM_FRAME_DM, dlc->rd_dlci); - rfcomm_dlc_close(dlc, ECONNABORTED); - break; - } - - err = rfcomm_session_send_frame(rs, - RFCOMM_FRAME_UA, dlc->rd_dlci); - if (err) { - rfcomm_session_send_frame(rs, - RFCOMM_FRAME_DM, dlc->rd_dlci); - rfcomm_dlc_close(dlc, err); - break; - } - - err = rfcomm_dlc_open(dlc); - if (err) { - rfcomm_session_send_frame(rs, - RFCOMM_FRAME_DM, dlc->rd_dlci); - rfcomm_dlc_close(dlc, err); - break; - } - - break; - - case RFCOMM_DLC_WAIT_RECV_UA: - case RFCOMM_DLC_OPEN: /* already established */ - (*dlc->rd_proto->linkmode)(dlc->rd_upper, mode); - break; - - default: - break; - } - } -} - -/* - * Receive data from L2CAP layer for session. There is always exactly one - * RFCOMM frame contained in each L2CAP frame. - */ -static void -rfcomm_session_input(void *arg, struct mbuf *m) -{ - struct rfcomm_session *rs = arg; - int dlci, len, type, pf; - uint8_t fcs, b; - - KASSERT(m != NULL); - KASSERT(rs != NULL); - - /* - * UIH frames: FCS is only calculated on address and control fields - * For other frames: FCS is calculated on address, control and length - * Length may extend to two octets - */ - fcs = 0xff; - - if (m->m_pkthdr.len < 4) { - DPRINTF("short frame (%d), discarded\n", m->m_pkthdr.len); - goto done; - } - - /* address - one octet */ - m_copydata(m, 0, 1, &b); - m_adj(m, 1); - fcs = FCS(fcs, b); - dlci = RFCOMM_DLCI(b); - - /* control - one octet */ - m_copydata(m, 0, 1, &b); - m_adj(m, 1); - fcs = FCS(fcs, b); - type = RFCOMM_TYPE(b); - pf = RFCOMM_PF(b); - - /* length - may be two octets */ - m_copydata(m, 0, 1, &b); - m_adj(m, 1); - if (type != RFCOMM_FRAME_UIH) - fcs = FCS(fcs, b); - len = (b >> 1) & 0x7f; - - if (RFCOMM_EA(b) == 0) { - if (m->m_pkthdr.len < 2) { - DPRINTF("short frame (%d, EA = 0), discarded\n", - m->m_pkthdr.len); - goto done; - } - - m_copydata(m, 0, 1, &b); - m_adj(m, 1); - if (type != RFCOMM_FRAME_UIH) - fcs = FCS(fcs, b); - - len |= (b << 7); - } - - /* FCS byte is last octet in frame */ - m_copydata(m, m->m_pkthdr.len - 1, 1, &b); - m_adj(m, -1); - fcs = FCS(fcs, b); - - if (fcs != 0xcf) { - DPRINTF("Bad FCS value (%#2.2x), frame discarded\n", fcs); - goto done; - } - - DPRINTFN(10, "dlci %d, type %2.2x, len = %d\n", dlci, type, len); - - switch (type) { - case RFCOMM_FRAME_SABM: - if (pf) - rfcomm_session_recv_sabm(rs, dlci); - break; - - case RFCOMM_FRAME_DISC: - if (pf) - rfcomm_session_recv_disc(rs, dlci); - break; - - case RFCOMM_FRAME_UA: - if (pf) - rfcomm_session_recv_ua(rs, dlci); - break; - - case RFCOMM_FRAME_DM: - rfcomm_session_recv_dm(rs, dlci); - break; - - case RFCOMM_FRAME_UIH: - rfcomm_session_recv_uih(rs, dlci, pf, m, len); - return; /* (no release) */ - - default: - UNKNOWN(type); - break; - } - -done: - m_freem(m); -} - -/*********************************************************************** - * - * RFCOMM Session receive processing - */ - -/* - * rfcomm_session_recv_sabm(rfcomm_session, dlci) - * - * Set Asyncrhonous Balanced Mode - open the channel. - */ -static void -rfcomm_session_recv_sabm(struct rfcomm_session *rs, int dlci) -{ - struct rfcomm_dlc *dlc; - int err; - - DPRINTFN(5, "SABM(%d)\n", dlci); - - if (dlci == 0) { /* Open Session */ - rs->rs_state = RFCOMM_SESSION_OPEN; - rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, 0); - LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) { - if (dlc->rd_state == RFCOMM_DLC_WAIT_SESSION) - rfcomm_dlc_connect(dlc); - } - return; - } - - if (rs->rs_state != RFCOMM_SESSION_OPEN) { - DPRINTF("session was not even open!\n"); - return; - } - - /* validate direction bit */ - if ((IS_INITIATOR(rs) && !RFCOMM_DIRECTION(dlci)) - || (!IS_INITIATOR(rs) && RFCOMM_DIRECTION(dlci))) { - DPRINTF("Invalid direction bit on DLCI\n"); - return; - } - - /* - * look for our DLC - this may exist if we received PN - * already, or we may have to fabricate a new one. - */ - dlc = rfcomm_dlc_lookup(rs, dlci); - if (dlc == NULL) { - dlc = rfcomm_dlc_newconn(rs, dlci); - if (dlc == NULL) - return; /* (DM is sent) */ - } - - /* - * ..but if this DLC is not waiting to connect, they did - * something wrong, ignore it. - */ - if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT) - return; - - /* set link mode */ - err = rfcomm_dlc_setmode(dlc); - if (err == EINPROGRESS) { - dlc->rd_state = RFCOMM_DLC_WAIT_SEND_UA; - (*dlc->rd_proto->connecting)(dlc->rd_upper); - return; - } - if (err) - goto close; - - err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci); - if (err) - goto close; - - /* and mark it open */ - err = rfcomm_dlc_open(dlc); - if (err) - goto close; - - return; - -close: - rfcomm_dlc_close(dlc, err); -} - -/* - * Receive Disconnect Command - */ -static void -rfcomm_session_recv_disc(struct rfcomm_session *rs, int dlci) -{ - struct rfcomm_dlc *dlc; - - DPRINTFN(5, "DISC(%d)\n", dlci); - - if (dlci == 0) { - /* - * Disconnect Session - * - * We set the session state to CLOSED so that when - * the UA frame is clear the session will be closed - * automatically. We wont bother to close any DLC's - * just yet as there should be none. In the unlikely - * event that something is left, it will get flushed - * out as the session goes down. - */ - rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, 0); - rs->rs_state = RFCOMM_SESSION_CLOSED; - return; - } - - dlc = rfcomm_dlc_lookup(rs, dlci); - if (dlc == NULL) { - rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci); - return; - } - - rfcomm_dlc_close(dlc, ECONNRESET); - rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci); -} - -/* - * Receive Unnumbered Acknowledgement Response - * - * This should be a response to a DISC or SABM frame that we - * have previously sent. If unexpected, ignore it. - */ -static void -rfcomm_session_recv_ua(struct rfcomm_session *rs, int dlci) -{ - struct rfcomm_dlc *dlc; - - DPRINTFN(5, "UA(%d)\n", dlci); - - if (dlci == 0) { - switch (rs->rs_state) { - case RFCOMM_SESSION_WAIT_CONNECT: /* We sent SABM */ - timeout_del(&rs->rs_timeout); - rs->rs_state = RFCOMM_SESSION_OPEN; - LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) { - if (dlc->rd_state == RFCOMM_DLC_WAIT_SESSION) - rfcomm_dlc_connect(dlc); - } - break; - - case RFCOMM_SESSION_WAIT_DISCONNECT: /* We sent DISC */ - timeout_del(&rs->rs_timeout); - rs->rs_state = RFCOMM_SESSION_CLOSED; - l2cap_disconnect(rs->rs_l2cap, 0); - break; - - default: - DPRINTF("Received spurious UA(0)!\n"); - break; - } - - return; - } - - /* - * If we have no DLC on this dlci, we may have aborted - * without shutting down properly, so check if the session - * needs disconnecting. - */ - dlc = rfcomm_dlc_lookup(rs, dlci); - if (dlc == NULL) - goto check; - - switch (dlc->rd_state) { - case RFCOMM_DLC_WAIT_RECV_UA: /* We sent SABM */ - rfcomm_dlc_open(dlc); - return; - - case RFCOMM_DLC_WAIT_DISCONNECT: /* We sent DISC */ - rfcomm_dlc_close(dlc, 0); - break; - - default: - DPRINTF("Received spurious UA(%d)!\n", dlci); - return; - } - -check: /* last one out turns out the light */ - if (LIST_EMPTY(&rs->rs_dlcs)) { - rs->rs_state = RFCOMM_SESSION_WAIT_DISCONNECT; - rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, 0); - timeout_add_sec(&rs->rs_timeout, rfcomm_ack_timeout); - } -} - -/* - * Receive Disconnected Mode Response - * - * If this does not apply to a known DLC then we may ignore it. - */ -static void -rfcomm_session_recv_dm(struct rfcomm_session *rs, int dlci) -{ - struct rfcomm_dlc *dlc; - - DPRINTFN(5, "DM(%d)\n", dlci); - - dlc = rfcomm_dlc_lookup(rs, dlci); - if (dlc == NULL) - return; - - if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT) - rfcomm_dlc_close(dlc, ECONNREFUSED); - else - rfcomm_dlc_close(dlc, ECONNRESET); -} - -/* - * Receive Unnumbered Information with Header check (MCC or data packet) - */ -static void -rfcomm_session_recv_uih(struct rfcomm_session *rs, int dlci, - int pf, struct mbuf *m, int len) -{ - struct rfcomm_dlc *dlc; - uint8_t credits = 0; - - DPRINTFN(10, "UIH(%d)\n", dlci); - - if (dlci == 0) { - rfcomm_session_recv_mcc(rs, m); - return; - } - - if (m->m_pkthdr.len != len + pf) { - DPRINTF("Bad Frame Length (%d), frame discarded\n", - m->m_pkthdr.len); - - goto discard; - } - - dlc = rfcomm_dlc_lookup(rs, dlci); - if (dlc == NULL) { - DPRINTF("UIH received for non existent DLC, discarded\n"); - rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci); - goto discard; - } - - if (dlc->rd_state != RFCOMM_DLC_OPEN) { - DPRINTF("non-open DLC (state = %d), discarded\n", - dlc->rd_state); - goto discard; - } - - /* if PF is set, credits were included */ - if (rs->rs_flags & RFCOMM_SESSION_CFC) { - if (pf != 0) { - if (m->m_pkthdr.len < sizeof(credits)) { - DPRINTF("Bad PF value, UIH discarded\n"); - goto discard; - } - - m_copydata(m, 0, sizeof(credits), &credits); - m_adj(m, sizeof(credits)); - - dlc->rd_txcred += credits; - - if (credits > 0 && dlc->rd_txbuf != NULL) - rfcomm_dlc_start(dlc); - } - - if (len == 0) - goto discard; - - if (dlc->rd_rxcred == 0) { - DPRINTF("Credit limit reached, UIH discarded\n"); - goto discard; - } - - if (len > dlc->rd_rxsize) { - DPRINTF("UIH frame exceeds rxsize, discarded\n"); - goto discard; - } - - dlc->rd_rxcred--; - dlc->rd_rxsize -= len; - } - - (*dlc->rd_proto->input)(dlc->rd_upper, m); - return; - -discard: - m_freem(m); -} - -/* - * Receive Multiplexer Control Command - */ -static void -rfcomm_session_recv_mcc(struct rfcomm_session *rs, struct mbuf *m) -{ - int type, cr, len; - uint8_t b; - - /* - * Extract MCC header. - * - * Fields are variable length using extension bit = 1 to signify the - * last octet in the sequence. - * - * Only single octet types are defined in TS 07.10/RFCOMM spec - * - * Length can realistically only use 15 bits (max RFCOMM MTU) - */ - if (m->m_pkthdr.len < sizeof(b)) { - DPRINTF("Short MCC header, discarded\n"); - goto release; - } - - m_copydata(m, 0, sizeof(b), &b); - m_adj(m, sizeof(b)); - - if (RFCOMM_EA(b) == 0) { /* verify no extensions */ - DPRINTF("MCC type EA = 0, discarded\n"); - goto release; - } - - type = RFCOMM_MCC_TYPE(b); - cr = RFCOMM_CR(b); - - len = 0; - do { - if (m->m_pkthdr.len < sizeof(b)) { - DPRINTF("Short MCC header, discarded\n"); - goto release; - } - - m_copydata(m, 0, sizeof(b), &b); - m_adj(m, sizeof(b)); - - len = (len << 7) | (b >> 1); - len = min(len, RFCOMM_MTU_MAX); - } while (RFCOMM_EA(b) == 0); - - if (len != m->m_pkthdr.len) { - DPRINTF("Incorrect MCC length, discarded\n"); - goto release; - } - - DPRINTFN(2, "MCC %s type %2.2x (%d bytes)\n", - (cr ? "command" : "response"), type, len); - - /* - * pass to command handler - */ - switch(type) { - case RFCOMM_MCC_TEST: /* Test */ - rfcomm_session_recv_mcc_test(rs, cr, m); - break; - - case RFCOMM_MCC_FCON: /* Flow Control On */ - rfcomm_session_recv_mcc_fcon(rs, cr); - break; - - case RFCOMM_MCC_FCOFF: /* Flow Control Off */ - rfcomm_session_recv_mcc_fcoff(rs, cr); - break; - - case RFCOMM_MCC_MSC: /* Modem Status Command */ - rfcomm_session_recv_mcc_msc(rs, cr, m); - break; - - case RFCOMM_MCC_RPN: /* Remote Port Negotiation */ - rfcomm_session_recv_mcc_rpn(rs, cr, m); - break; - - case RFCOMM_MCC_RLS: /* Remote Line Status */ - rfcomm_session_recv_mcc_rls(rs, cr, m); - break; - - case RFCOMM_MCC_PN: /* Parameter Negotiation */ - rfcomm_session_recv_mcc_pn(rs, cr, m); - break; - - case RFCOMM_MCC_NSC: /* Non Supported Command */ - rfcomm_session_recv_mcc_nsc(rs, cr, m); - break; - - default: - b = RFCOMM_MKMCC_TYPE(cr, type); - rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_NSC, &b, sizeof(b)); - } - -release: - m_freem(m); -} - -/* - * process TEST command/response - */ -static void -rfcomm_session_recv_mcc_test(struct rfcomm_session *rs, int cr, struct mbuf *m) -{ - void *data; - int len; - - if (cr == 0) /* ignore ack */ - return; - - /* - * we must send all the data they included back as is - */ - - len = m->m_pkthdr.len; - if (len > RFCOMM_MTU_MAX) - return; - - data = malloc(len, M_BLUETOOTH, M_NOWAIT); - if (data == NULL) - return; - - m_copydata(m, 0, len, data); - rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_TEST, data, len); - free(data, M_BLUETOOTH); -} - -/* - * process Flow Control ON command/response - */ -static void -rfcomm_session_recv_mcc_fcon(struct rfcomm_session *rs, int cr) -{ - - if (cr == 0) /* ignore ack */ - return; - - rs->rs_flags |= RFCOMM_SESSION_RFC; - rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_FCON, NULL, 0); -} - -/* - * process Flow Control OFF command/response - */ -static void -rfcomm_session_recv_mcc_fcoff(struct rfcomm_session *rs, int cr) -{ - - if (cr == 0) /* ignore ack */ - return; - - rs->rs_flags &= ~RFCOMM_SESSION_RFC; - rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_FCOFF, NULL, 0); -} - -/* - * process Modem Status Command command/response - */ -static void -rfcomm_session_recv_mcc_msc(struct rfcomm_session *rs, int cr, struct mbuf *m) -{ - struct rfcomm_mcc_msc msc; /* (3 octets) */ - struct rfcomm_dlc *dlc; - int len = 0; - - /* [ADDRESS] */ - if (m->m_pkthdr.len < sizeof(msc.address)) - return; - - m_copydata(m, 0, sizeof(msc.address), &msc.address); - m_adj(m, sizeof(msc.address)); - len += sizeof(msc.address); - - dlc = rfcomm_dlc_lookup(rs, RFCOMM_DLCI(msc.address)); - - if (cr == 0) { /* ignore acks */ - if (dlc != NULL) - timeout_del(&dlc->rd_timeout); - - return; - } - - if (dlc == NULL) { - rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, - RFCOMM_DLCI(msc.address)); - return; - } - - /* [SIGNALS] */ - if (m->m_pkthdr.len < sizeof(msc.modem)) - return; - - m_copydata(m, 0, sizeof(msc.modem), &msc.modem); - m_adj(m, sizeof(msc.modem)); - len += sizeof(msc.modem); - - dlc->rd_rmodem = msc.modem; - /* XXX how do we signal this upstream? */ - - if (RFCOMM_EA(msc.modem) == 0) { - if (m->m_pkthdr.len < sizeof(msc.brk)) - return; - - m_copydata(m, 0, sizeof(msc.brk), &msc.brk); - m_adj(m, sizeof(msc.brk)); - len += sizeof(msc.brk); - - /* XXX how do we signal this upstream? */ - } - - rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_MSC, &msc, len); -} - -/* - * process Remote Port Negotiation command/response - */ -static void -rfcomm_session_recv_mcc_rpn(struct rfcomm_session *rs, int cr, struct mbuf *m) -{ - struct rfcomm_mcc_rpn rpn; - uint16_t mask; - - if (cr == 0) /* ignore ack */ - return; - - /* default values */ - rpn.bit_rate = RFCOMM_RPN_BR_9600; - rpn.line_settings = RFCOMM_RPN_8_N_1; - rpn.flow_control = RFCOMM_RPN_FLOW_NONE; - rpn.xon_char = RFCOMM_RPN_XON_CHAR; - rpn.xoff_char = RFCOMM_RPN_XOFF_CHAR; - - if (m->m_pkthdr.len == sizeof(rpn)) { - m_copydata(m, 0, sizeof(rpn), (caddr_t)&rpn); - rpn.param_mask = RFCOMM_RPN_PM_ALL; - } else if (m->m_pkthdr.len == 1) { - m_copydata(m, 0, 1, (caddr_t)&rpn); - rpn.param_mask = letoh16(rpn.param_mask); - } else { - DPRINTF("Bad RPN length (%d)\n", m->m_pkthdr.len); - return; - } - - mask = 0; - - if (rpn.param_mask & RFCOMM_RPN_PM_RATE) - mask |= RFCOMM_RPN_PM_RATE; - - if (rpn.param_mask & RFCOMM_RPN_PM_DATA - && RFCOMM_RPN_DATA_BITS(rpn.line_settings) == RFCOMM_RPN_DATA_8) - mask |= RFCOMM_RPN_PM_DATA; - - if (rpn.param_mask & RFCOMM_RPN_PM_STOP - && RFCOMM_RPN_STOP_BITS(rpn.line_settings) == RFCOMM_RPN_STOP_1) - mask |= RFCOMM_RPN_PM_STOP; - - if (rpn.param_mask & RFCOMM_RPN_PM_PARITY - && RFCOMM_RPN_PARITY(rpn.line_settings) == RFCOMM_RPN_PARITY_NONE) - mask |= RFCOMM_RPN_PM_PARITY; - - if (rpn.param_mask & RFCOMM_RPN_PM_XON - && rpn.xon_char == RFCOMM_RPN_XON_CHAR) - mask |= RFCOMM_RPN_PM_XON; - - if (rpn.param_mask & RFCOMM_RPN_PM_XOFF - && rpn.xoff_char == RFCOMM_RPN_XOFF_CHAR) - mask |= RFCOMM_RPN_PM_XOFF; - - if (rpn.param_mask & RFCOMM_RPN_PM_FLOW - && rpn.flow_control == RFCOMM_RPN_FLOW_NONE) - mask |= RFCOMM_RPN_PM_FLOW; - - rpn.param_mask = htole16(mask); - - rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_RPN, &rpn, sizeof(rpn)); -} - -/* - * process Remote Line Status command/response - */ -static void -rfcomm_session_recv_mcc_rls(struct rfcomm_session *rs, int cr, struct mbuf *m) -{ - struct rfcomm_mcc_rls rls; - - if (cr == 0) /* ignore ack */ - return; - - if (m->m_pkthdr.len != sizeof(rls)) { - DPRINTF("Bad RLS length %d\n", m->m_pkthdr.len); - return; - } - - m_copydata(m, 0, sizeof(rls), (caddr_t)&rls); - - /* - * So far as I can tell, we just send back what - * they sent us. This signifies errors that seem - * irrelevent for RFCOMM over L2CAP. - */ - rls.address |= 0x03; /* EA = 1, CR = 1 */ - rls.status &= 0x0f; /* only 4 bits valid */ - - rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_RLS, &rls, sizeof(rls)); -} - -/* - * process Parameter Negotiation command/response - */ -static void -rfcomm_session_recv_mcc_pn(struct rfcomm_session *rs, int cr, struct mbuf *m) -{ - struct rfcomm_dlc *dlc; - struct rfcomm_mcc_pn pn; - int err; - - if (m->m_pkthdr.len != sizeof(pn)) { - DPRINTF("Bad PN length %d\n", m->m_pkthdr.len); - return; - } - - m_copydata(m, 0, sizeof(pn), (caddr_t)&pn); - - pn.dlci &= 0x3f; - pn.mtu = letoh16(pn.mtu); - - dlc = rfcomm_dlc_lookup(rs, pn.dlci); - if (cr) { /* Command */ - /* - * If there is no DLC present, this is a new - * connection so attempt to make one - */ - if (dlc == NULL) { - dlc = rfcomm_dlc_newconn(rs, pn.dlci); - if (dlc == NULL) - return; /* (DM is sent) */ - } - - /* accept any valid MTU, and offer it back */ - pn.mtu = min(pn.mtu, RFCOMM_MTU_MAX); - pn.mtu = min(pn.mtu, rs->rs_mtu); - pn.mtu = max(pn.mtu, RFCOMM_MTU_MIN); - dlc->rd_mtu = pn.mtu; - pn.mtu = htole16(pn.mtu); - - /* credits are only set before DLC is open */ - if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT - && (pn.flow_control & 0xf0) == 0xf0) { - rs->rs_flags |= RFCOMM_SESSION_CFC; - dlc->rd_txcred = pn.credits & 0x07; - - dlc->rd_rxcred = (dlc->rd_rxsize / dlc->rd_mtu); - dlc->rd_rxcred = min(dlc->rd_rxcred, - RFCOMM_CREDITS_DEFAULT); - - pn.flow_control = 0xe0; - pn.credits = dlc->rd_rxcred; - } else { - pn.flow_control = 0x00; - pn.credits = 0x00; - } - - /* unused fields must be ignored and set to zero */ - pn.ack_timer = 0; - pn.max_retrans = 0; - - /* send our response */ - err = rfcomm_session_send_mcc(rs, 0, - RFCOMM_MCC_PN, &pn, sizeof(pn)); - if (err) - goto close; - - } else { /* Response */ - /* ignore responses with no matching DLC */ - if (dlc == NULL) - return; - - timeout_del(&dlc->rd_timeout); - - if (pn.mtu > RFCOMM_MTU_MAX || pn.mtu > dlc->rd_mtu) { - dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT; - err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, - pn.dlci); - if (err) - goto close; - - timeout_add_sec(&dlc->rd_timeout, rfcomm_ack_timeout); - return; - } - dlc->rd_mtu = pn.mtu; - - /* if DLC is not waiting to connect, we are done */ - if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT) - return; - - /* set initial credits according to RFCOMM spec */ - if ((pn.flow_control & 0xf0) == 0xe0) { - rs->rs_flags |= RFCOMM_SESSION_CFC; - dlc->rd_txcred = (pn.credits & 0x07); - } - - timeout_add_sec(&dlc->rd_timeout, rfcomm_ack_timeout); - - /* set link mode */ - err = rfcomm_dlc_setmode(dlc); - if (err == EINPROGRESS) { - dlc->rd_state = RFCOMM_DLC_WAIT_SEND_SABM; - (*dlc->rd_proto->connecting)(dlc->rd_upper); - return; - } - if (err) - goto close; - - /* we can proceed now */ - err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, pn.dlci); - if (err) - goto close; - - dlc->rd_state = RFCOMM_DLC_WAIT_RECV_UA; - } - return; - -close: - rfcomm_dlc_close(dlc, err); -} - -/* - * process Non Supported Command command/response - */ -static void -rfcomm_session_recv_mcc_nsc(struct rfcomm_session *rs, - int cr, struct mbuf *m) -{ - struct rfcomm_dlc *dlc, *next; - - /* - * Since we did nothing that is not mandatory, - * we just abort the whole session.. - */ - - next = LIST_FIRST(&rs->rs_dlcs); - while ((dlc = next) != NULL) { - next = LIST_NEXT(dlc, rd_next); - rfcomm_dlc_close(dlc, ECONNABORTED); - } - - rfcomm_session_free(rs); -} - -/*********************************************************************** - * - * RFCOMM Session outward frame/uih/mcc building - */ - -/* - * SABM/DISC/DM/UA frames are all minimal and mostly identical. - */ -int -rfcomm_session_send_frame(struct rfcomm_session *rs, int type, int dlci) -{ - struct rfcomm_cmd_hdr *hdr; - struct rfcomm_credit *credit; - struct mbuf *m; - uint8_t fcs, cr; - - credit = pool_get(&rfcomm_credit_pool, PR_NOWAIT); - if (credit == NULL) - return ENOMEM; - - m = m_gethdr(M_DONTWAIT, MT_DATA); - if (m == NULL) { - pool_put(&rfcomm_credit_pool, credit); - return ENOMEM; - } - - /* - * The CR (command/response) bit identifies the frame either as a - * commmand or a response and is used along with the DLCI to form - * the address. Commands contain the non-initiator address, whereas - * responses contain the initiator address, so the CR value is - * also dependent on the session direction. - */ - if (type == RFCOMM_FRAME_UA || type == RFCOMM_FRAME_DM) - cr = IS_INITIATOR(rs) ? 0 : 1; - else - cr = IS_INITIATOR(rs) ? 1 : 0; - - hdr = mtod(m, struct rfcomm_cmd_hdr *); - hdr->address = RFCOMM_MKADDRESS(cr, dlci); - hdr->control = RFCOMM_MKCONTROL(type, 1); /* PF = 1 */ - hdr->length = (0x00 << 1) | 0x01; /* len = 0x00, EA = 1 */ - - fcs = 0xff; - fcs = FCS(fcs, hdr->address); - fcs = FCS(fcs, hdr->control); - fcs = FCS(fcs, hdr->length); - fcs = 0xff - fcs; /* ones complement */ - hdr->fcs = fcs; - - m->m_pkthdr.len = m->m_len = sizeof(struct rfcomm_cmd_hdr); - - /* empty credit note */ - credit->rc_dlc = NULL; - credit->rc_len = m->m_pkthdr.len; - SIMPLEQ_INSERT_TAIL(&rs->rs_credits, credit, rc_next); - - DPRINTFN(5, "dlci %d type %2.2x (%d bytes, fcs=%#2.2x)\n", - dlci, type, m->m_pkthdr.len, fcs); - - return l2cap_send(rs->rs_l2cap, m); -} - -/* - * rfcomm_session_send_uih(rfcomm_session, rfcomm_dlc, credits, mbuf) - * - * UIH frame is per DLC data or Multiplexer Control Commands - * when no DLC is given. Data mbuf is optional (just credits - * will be sent in that case) - */ -int -rfcomm_session_send_uih(struct rfcomm_session *rs, struct rfcomm_dlc *dlc, - int credits, struct mbuf *m) -{ - struct rfcomm_credit *credit; - struct mbuf *m0 = NULL; - int err, len; - uint8_t fcs, *hdr; - - KASSERT(rs != NULL); - - len = (m == NULL) ? 0 : m->m_pkthdr.len; - KASSERT(!(credits == 0 && len == 0)); - - /* - * Make a credit note for the completion notification - */ - credit = pool_get(&rfcomm_credit_pool, PR_NOWAIT); - if (credit == NULL) - goto nomem; - - credit->rc_len = len; - credit->rc_dlc = dlc; - - /* - * Wrap UIH frame information around payload. - * - * [ADDRESS] [CONTROL] [LENGTH] [CREDITS] [...] [FCS] - * - * Address is one octet. - * Control is one octet. - * Length is one or two octets. - * Credits may be one octet. - * - * FCS is one octet and calculated on address and - * control octets only. - * - * If there are credits to be sent, we will set the PF - * flag and include them in the frame. - */ - m0 = m_gethdr(M_DONTWAIT, MT_DATA); - if (m0 == NULL) - goto nomem; - - MH_ALIGN(m0, 5); /* (max 5 header octets) */ - hdr = mtod(m0, uint8_t *); - - /* CR bit is set according to the initiator of the session */ - *hdr = RFCOMM_MKADDRESS((IS_INITIATOR(rs) ? 1 : 0), - (dlc ? dlc->rd_dlci : 0)); - fcs = FCS(0xff, *hdr); - hdr++; - - /* PF bit is set if credits are being sent */ - *hdr = RFCOMM_MKCONTROL(RFCOMM_FRAME_UIH, (credits > 0 ? 1 : 0)); - fcs = FCS(fcs, *hdr); - hdr++; - - if (len < (1 << 7)) { - *hdr++ = ((len << 1) & 0xfe) | 0x01; /* 7 bits, EA = 1 */ - } else { - *hdr++ = ((len << 1) & 0xfe); /* 7 bits, EA = 0 */ - *hdr++ = ((len >> 7) & 0xff); /* 8 bits, no EA */ - } - - if (credits > 0) - *hdr++ = (uint8_t)credits; - - m0->m_len = hdr - mtod(m0, uint8_t *); - - /* Append payload */ - m0->m_next = m; - m = NULL; - - m0->m_pkthdr.len = m0->m_len + len; - - /* Append FCS */ - fcs = 0xff - fcs; /* ones complement */ - len = m0->m_pkthdr.len; - m_copyback(m0, len, sizeof(fcs), &fcs, M_NOWAIT); - if (m0->m_pkthdr.len != len + sizeof(fcs)) - goto nomem; - - DPRINTFN(10, "dlci %d, pktlen %d (%d data, %d credits), fcs=%#2.2x\n", - dlc ? dlc->rd_dlci : 0, m0->m_pkthdr.len, credit->rc_len, - credits, fcs); - - /* - * UIH frame ready to go.. - */ - err = l2cap_send(rs->rs_l2cap, m0); - if (err) - goto fail; - - SIMPLEQ_INSERT_TAIL(&rs->rs_credits, credit, rc_next); - return 0; - -nomem: - err = ENOMEM; - - if (m0 != NULL) - m_freem(m0); - - if (m != NULL) - m_freem(m); - -fail: - if (credit != NULL) - pool_put(&rfcomm_credit_pool, credit); - - return err; -} - -/* - * send Multiplexer Control Command (or Response) on session - */ -int -rfcomm_session_send_mcc(struct rfcomm_session *rs, int cr, - uint8_t type, void *data, int len) -{ - struct mbuf *m; - uint8_t *hdr; - int hlen; - - m = m_gethdr(M_DONTWAIT, MT_DATA); - if (m == NULL) - return ENOMEM; - - hdr = mtod(m, uint8_t *); - - /* - * Technically the type field can extend past one octet, but none - * currently defined will do that. - */ - *hdr++ = RFCOMM_MKMCC_TYPE(cr, type); - - /* - * In the frame, the max length size is 2 octets (15 bits) whereas - * no max length size is specified for MCC commands. We must allow - * for 3 octets since for MCC frames we use 7 bits + EA in each. - * - * Only test data can possibly be that big. - * - * XXX Should we check this against the MTU? - */ - if (len < (1 << 7)) { - *hdr++ = ((len << 1) & 0xfe) | 0x01; /* 7 bits, EA = 1 */ - } else if (len < (1 << 14)) { - *hdr++ = ((len << 1) & 0xfe); /* 7 bits, EA = 0 */ - *hdr++ = ((len >> 6) & 0xfe) | 0x01; /* 7 bits, EA = 1 */ - } else if (len < (1 << 15)) { - *hdr++ = ((len << 1) & 0xfe); /* 7 bits, EA = 0 */ - *hdr++ = ((len >> 6) & 0xfe); /* 7 bits, EA = 0 */ - *hdr++ = ((len >> 13) & 0x02) | 0x01; /* 1 bit, EA = 1 */ - } else { - DPRINTF("incredible length! (%d)\n", len); - m_freem(m); - return EMSGSIZE; - } - - /* - * add command data (to same mbuf if possible) - */ - hlen = hdr - mtod(m, uint8_t *); - - if (len > 0) { - m->m_pkthdr.len = m->m_len = MHLEN; - m_copyback(m, hlen, len, data, M_NOWAIT); - if (m->m_pkthdr.len != max(MHLEN, hlen + len)) { - m_freem(m); - return ENOMEM; - } - } - - m->m_pkthdr.len = hlen + len; - m->m_len = min(MHLEN, m->m_pkthdr.len); - - DPRINTFN(5, "%s type %2.2x len %d\n", - (cr ? "command" : "response"), type, m->m_pkthdr.len); - - return rfcomm_session_send_uih(rs, NULL, 0, m); -} diff --git a/sys/netbt/rfcomm_socket.c b/sys/netbt/rfcomm_socket.c deleted file mode 100644 index 951d15fe5dc..00000000000 --- a/sys/netbt/rfcomm_socket.c +++ /dev/null @@ -1,420 +0,0 @@ -/* $OpenBSD: rfcomm_socket.c,v 1.5 2009/11/21 13:05:32 guenther Exp $ */ -/* $NetBSD: rfcomm_socket.c,v 1.10 2008/08/06 15:01:24 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* load symbolic names */ -#ifdef BLUETOOTH_DEBUG -#define PRUREQUESTS -#define PRCOREQUESTS -#endif - -#include <sys/param.h> -#include <sys/domain.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> /* XXX for EPASSTHROUGH */ -#include <netbt/rfcomm.h> - -/**************************************************************************** - * - * RFCOMM SOCK_STREAM Sockets - serial line emulation - * - */ - -static void rfcomm_connecting(void *); -static void rfcomm_connected(void *); -static void rfcomm_disconnected(void *, int); -static void *rfcomm_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); -static void rfcomm_complete(void *, int); -static void rfcomm_linkmode(void *, int); -static void rfcomm_input(void *, struct mbuf *); - -static const struct btproto rfcomm_proto = { - rfcomm_connecting, - rfcomm_connected, - rfcomm_disconnected, - rfcomm_newconn, - rfcomm_complete, - rfcomm_linkmode, - rfcomm_input, -}; - -/* sysctl variables */ -int rfcomm_sendspace = 4096; -int rfcomm_recvspace = 4096; - -/* - * User Request. - * up is socket - * m is either - * optional mbuf chain containing message - * ioctl command (PRU_CONTROL) - * nam is either - * optional mbuf chain containing an address - * ioctl data (PRU_CONTROL) - * optionally protocol number (PRU_ATTACH) - * message flags (PRU_RCVD) - * ctl is either - * optional mbuf chain containing socket options - * optional interface pointer (PRU_CONTROL, PRU_PURGEIF) - * l is pointer to process requesting action (if any) - * - * we are responsible for disposing of m and ctl if - * they are mbuf chains - */ -int -rfcomm_usrreq(struct socket *up, int req, struct mbuf *m, - struct mbuf *nam, struct mbuf *ctl, struct proc *p) -{ - struct rfcomm_dlc *pcb = up->so_pcb; - struct sockaddr_bt *sa; - struct mbuf *m0; - int err = 0; - -#ifdef notyet /* XXX */ - DPRINTFN(2, "%s\n", prurequests[req]); -#endif - - switch (req) { - case PRU_CONTROL: - return EPASSTHROUGH; - -#ifdef notyet /* XXX */ - case PRU_PURGEIF: - return EOPNOTSUPP; -#endif - - case PRU_ATTACH: - /* XXX solock() and bt_lock fiddling in NetBSD */ - if (pcb != NULL) - return EINVAL; - /* - * Since we have nothing to add, we attach the DLC - * structure directly to our PCB pointer. - */ - err = soreserve(up, rfcomm_sendspace, rfcomm_recvspace); - if (err) - return err; - - err = rfcomm_attach((struct rfcomm_dlc **)&up->so_pcb, - &rfcomm_proto, up); - if (err) - return err; - - err = rfcomm_rcvd(up->so_pcb, sbspace(&up->so_rcv)); - if (err) { - rfcomm_detach((struct rfcomm_dlc **)&up->so_pcb); - return err; - } - - return 0; - } - - if (pcb == NULL) { - err = EINVAL; - goto release; - } - - switch(req) { - case PRU_DISCONNECT: - soisdisconnecting(up); - return rfcomm_disconnect(pcb, up->so_linger); - - case PRU_ABORT: - rfcomm_disconnect(pcb, 0); - soisdisconnected(up); - /* fall through to */ - case PRU_DETACH: - return rfcomm_detach((struct rfcomm_dlc **)&up->so_pcb); - - case PRU_BIND: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - - if (sa->bt_len != sizeof(struct sockaddr_bt)) - return EINVAL; - - if (sa->bt_family != AF_BLUETOOTH) - return EAFNOSUPPORT; - - return rfcomm_bind(pcb, sa); - - case PRU_CONNECT: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - - if (sa->bt_len != sizeof(struct sockaddr_bt)) - return EINVAL; - - if (sa->bt_family != AF_BLUETOOTH) - return EAFNOSUPPORT; - - soisconnecting(up); - return rfcomm_connect(pcb, sa); - - case PRU_PEERADDR: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - nam->m_len = sizeof(struct sockaddr_bt); - return rfcomm_peeraddr(pcb, sa); - - case PRU_SOCKADDR: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - nam->m_len = sizeof(struct sockaddr_bt); - return rfcomm_sockaddr(pcb, sa); - - case PRU_SHUTDOWN: - socantsendmore(up); - break; - - case PRU_SEND: - KASSERT(m != NULL); - - if (ctl) /* no use for that */ - m_freem(ctl); - - m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if (m0 == NULL) - return ENOMEM; - - sbappendstream(&up->so_snd, m); - - return rfcomm_send(pcb, m0); - - case PRU_SENSE: - return 0; /* (no release) */ - - case PRU_RCVD: - return rfcomm_rcvd(pcb, sbspace(&up->so_rcv)); - - case PRU_RCVOOB: - return EOPNOTSUPP; /* (no release) */ - - case PRU_LISTEN: - return rfcomm_listen(pcb); - - case PRU_ACCEPT: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - nam->m_len = sizeof(struct sockaddr_bt); - return rfcomm_peeraddr(pcb, sa); - - case PRU_CONNECT2: - case PRU_SENDOOB: - case PRU_FASTTIMO: - case PRU_SLOWTIMO: - case PRU_PROTORCV: - case PRU_PROTOSEND: - err = EOPNOTSUPP; - break; - - default: - UNKNOWN(req); - err = EOPNOTSUPP; - break; - } - -release: - if (m) m_freem(m); - if (ctl) m_freem(ctl); - return err; -} - -/* - * rfcomm_ctloutput(request, socket, level, optname, opt) - * - */ -int -rfcomm_ctloutput(int req, struct socket *so, int level, - int optname, struct mbuf **opt) -{ - struct rfcomm_dlc *pcb = so->so_pcb; - struct mbuf *m; - int err = 0; - -#ifdef notyet /* XXX */ - DPRINTFN(2, "%s\n", prcorequests[req]); -#endif - - if (pcb == NULL) - return EINVAL; - - if (level != BTPROTO_RFCOMM) { - err = EINVAL; - if (req == PRCO_SETOPT && *opt) - m_free(*opt); - } else switch(req) { - case PRCO_GETOPT: - m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = rfcomm_getopt(pcb, optname, mtod(m, void *)); - if (m->m_len == 0) { - m_freem(m); - m = NULL; - err = ENOPROTOOPT; - } - *opt = m; - break; - - case PRCO_SETOPT: - m = *opt; - err = rfcomm_setopt(pcb, optname, m); - m_freem(m); - break; - - default: - err = ENOPROTOOPT; - break; - } - - return err; -} - -/********************************************************************** - * - * RFCOMM callbacks - */ - -static void -rfcomm_connecting(void *arg) -{ - /* struct socket *so = arg; */ - - KASSERT(arg != NULL); - DPRINTF("Connecting\n"); -} - -static void -rfcomm_connected(void *arg) -{ - struct socket *so = arg; - - KASSERT(so != NULL); - DPRINTF("Connected\n"); - soisconnected(so); -} - -static void -rfcomm_disconnected(void *arg, int err) -{ - struct socket *so = arg; - - KASSERT(so != NULL); - DPRINTF("Disconnected\n"); - - so->so_error = err; - soisdisconnected(so); -} - -static void * -rfcomm_newconn(void *arg, struct sockaddr_bt *laddr, - struct sockaddr_bt *raddr) -{ - struct socket *so = arg; - - DPRINTF("New Connection\n"); - so = sonewconn(so, 0); - if (so == NULL) - return NULL; - - soisconnecting(so); - - return so->so_pcb; -} - -/* - * rfcomm_complete(rfcomm_dlc, length) - * - * length bytes are sent and may be removed from socket buffer - */ -static void -rfcomm_complete(void *arg, int length) -{ - struct socket *so = arg; - - sbdrop(&so->so_snd, length); - sowwakeup(so); -} - -/* - * rfcomm_linkmode(rfcomm_dlc, new) - * - * link mode change notification. - */ -static void -rfcomm_linkmode(void *arg, int new) -{ - struct socket *so = arg; - int mode; - - DPRINTF("auth %s, encrypt %s, secure %s\n", - (new & RFCOMM_LM_AUTH ? "on" : "off"), - (new & RFCOMM_LM_ENCRYPT ? "on" : "off"), - (new & RFCOMM_LM_SECURE ? "on" : "off")); - - (void)rfcomm_getopt(so->so_pcb, SO_RFCOMM_LM, &mode); - if (((mode & RFCOMM_LM_AUTH) && !(new & RFCOMM_LM_AUTH)) - || ((mode & RFCOMM_LM_ENCRYPT) && !(new & RFCOMM_LM_ENCRYPT)) - || ((mode & RFCOMM_LM_SECURE) && !(new & RFCOMM_LM_SECURE))) - rfcomm_disconnect(so->so_pcb, 0); -} - -/* - * rfcomm_input(rfcomm_dlc, mbuf) - */ -static void -rfcomm_input(void *arg, struct mbuf *m) -{ - struct socket *so = arg; - - KASSERT(so != NULL); - - if (m->m_pkthdr.len > sbspace(&so->so_rcv)) { - printf("%s: %d bytes dropped (socket buffer full)\n", - __func__, m->m_pkthdr.len); - m_freem(m); - return; - } - - DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); - - sbappendstream(&so->so_rcv, m); - sorwakeup(so); -} diff --git a/sys/netbt/rfcomm_upper.c b/sys/netbt/rfcomm_upper.c deleted file mode 100644 index 19635350362..00000000000 --- a/sys/netbt/rfcomm_upper.c +++ /dev/null @@ -1,524 +0,0 @@ -/* $OpenBSD: rfcomm_upper.c,v 1.7 2009/11/21 13:05:32 guenther Exp $ */ -/* $NetBSD: rfcomm_upper.c,v 1.11 2008/08/06 15:01:24 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/l2cap.h> -#include <netbt/rfcomm.h> - -/**************************************************************************** - * - * RFCOMM DLC - Upper Protocol API - * - * Currently the only 'Port Emulation Entity' is the RFCOMM socket code - * but it is should be possible to provide a pseudo-device for a direct - * tty interface. - */ - -/* - * rfcomm_attach(handle, proto, upper) - * - * attach a new RFCOMM DLC to handle, populate with reasonable defaults - */ -int -rfcomm_attach(struct rfcomm_dlc **handle, - const struct btproto *proto, void *upper) -{ - struct rfcomm_dlc *dlc; - - KASSERT(handle != NULL); - KASSERT(proto != NULL); - KASSERT(upper != NULL); - - dlc = malloc(sizeof(*dlc), M_BLUETOOTH, M_NOWAIT | M_ZERO); - if (dlc == NULL) - return ENOMEM; - - dlc->rd_state = RFCOMM_DLC_CLOSED; - dlc->rd_mtu = rfcomm_mtu_default; - - dlc->rd_proto = proto; - dlc->rd_upper = upper; - - dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt); - dlc->rd_laddr.bt_family = AF_BLUETOOTH; - dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM; - - dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt); - dlc->rd_raddr.bt_family = AF_BLUETOOTH; - dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM; - - dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV; - - timeout_set(&dlc->rd_timeout, rfcomm_dlc_timeout, dlc); - - *handle = dlc; - return 0; -} - -/* - * rfcomm_bind(dlc, sockaddr) - * - * bind DLC to local address - */ -int -rfcomm_bind(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr) -{ - - memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt)); - return 0; -} - -/* - * rfcomm_sockaddr(dlc, sockaddr) - * - * return local address - */ -int -rfcomm_sockaddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr) -{ - - memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt)); - return 0; -} - -/* - * rfcomm_connect(dlc, sockaddr) - * - * Initiate connection of RFCOMM DLC to remote address. - */ -int -rfcomm_connect(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest) -{ - struct rfcomm_session *rs; - int err = 0; - - if (dlc->rd_state != RFCOMM_DLC_CLOSED) - return EISCONN; - - memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt)); - - if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN - || dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX - || bdaddr_any(&dlc->rd_raddr.bt_bdaddr)) - return EDESTADDRREQ; - - if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY) - dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM; - else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM - && (dlc->rd_raddr.bt_psm < 0x1001 - || L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm))) - return EINVAL; - - /* - * We are allowed only one RFCOMM session between any 2 Bluetooth - * devices, so see if there is a session already otherwise create - * one and set it connecting. - */ - rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr); - if (rs == NULL) { - rs = rfcomm_session_alloc(&rfcomm_session_active, - &dlc->rd_laddr); - if (rs == NULL) - return ENOMEM; - - rs->rs_flags |= RFCOMM_SESSION_INITIATOR; - rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT; - - err = l2cap_connect(rs->rs_l2cap, &dlc->rd_raddr); - if (err) { - rfcomm_session_free(rs); - return err; - } - - /* - * This session will start up automatically when its - * L2CAP channel is connected. - */ - } - - /* construct DLC */ - dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel); - if (rfcomm_dlc_lookup(rs, dlc->rd_dlci)) - return EBUSY; - - l2cap_sockaddr(rs->rs_l2cap, &dlc->rd_laddr); - - /* - * attach the DLC to the session and start it off - */ - dlc->rd_session = rs; - dlc->rd_state = RFCOMM_DLC_WAIT_SESSION; - LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next); - - if (rs->rs_state == RFCOMM_SESSION_OPEN) - err = rfcomm_dlc_connect(dlc); - - return err; -} - -/* - * rfcomm_peeraddr(dlc, sockaddr) - * - * return remote address - */ -int -rfcomm_peeraddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr) -{ - - memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt)); - return 0; -} - -/* - * rfcomm_disconnect(dlc, linger) - * - * disconnect RFCOMM DLC - */ -int -rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger) -{ - struct rfcomm_session *rs = dlc->rd_session; - int err = 0; - - KASSERT(dlc != NULL); - - switch (dlc->rd_state) { - case RFCOMM_DLC_CLOSED: - case RFCOMM_DLC_LISTEN: - return EINVAL; - - case RFCOMM_DLC_WAIT_SEND_UA: - err = rfcomm_session_send_frame(rs, - RFCOMM_FRAME_DM, dlc->rd_dlci); - - /* fall through */ - case RFCOMM_DLC_WAIT_SESSION: - case RFCOMM_DLC_WAIT_CONNECT: - case RFCOMM_DLC_WAIT_SEND_SABM: - rfcomm_dlc_close(dlc, 0); - break; - - case RFCOMM_DLC_OPEN: - if (dlc->rd_txbuf != NULL && linger != 0) { - dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN; - break; - } - - /* else fall through */ - case RFCOMM_DLC_WAIT_RECV_UA: - dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT; - err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, - dlc->rd_dlci); - timeout_add_sec(&dlc->rd_timeout, rfcomm_ack_timeout); - break; - - case RFCOMM_DLC_WAIT_DISCONNECT: - err = EALREADY; - break; - - default: - UNKNOWN(dlc->rd_state); - break; - } - - return err; -} - -/* - * rfcomm_detach(handle) - * - * detach RFCOMM DLC from handle - */ -int -rfcomm_detach(struct rfcomm_dlc **handle) -{ - struct rfcomm_dlc *dlc = *handle; - - if (dlc->rd_state != RFCOMM_DLC_CLOSED) - rfcomm_dlc_close(dlc, 0); - - if (dlc->rd_txbuf != NULL) { - m_freem(dlc->rd_txbuf); - dlc->rd_txbuf = NULL; - } - - dlc->rd_upper = NULL; - *handle = NULL; - - /* - * If callout is invoking we can't free the DLC so - * mark it and let the callout release it. - */ - if (timeout_triggered(&dlc->rd_timeout)) - dlc->rd_flags |= RFCOMM_DLC_DETACH; - else - free(dlc, M_BLUETOOTH); - - return 0; -} - -/* - * rfcomm_listen(dlc) - * - * This DLC is a listener. We look for an existing listening session - * with a matching address to attach to or else create a new one on - * the listeners list. If the ANY channel is given, allocate the first - * available for the session. - */ -int -rfcomm_listen(struct rfcomm_dlc *dlc) -{ - struct rfcomm_session *rs; - struct rfcomm_dlc *used; - struct sockaddr_bt addr; - int err, channel; - - if (dlc->rd_state != RFCOMM_DLC_CLOSED) - return EISCONN; - - if (dlc->rd_laddr.bt_channel != RFCOMM_CHANNEL_ANY - && (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN - || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX)) - return EADDRNOTAVAIL; - - if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY) - dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM; - else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM - && (dlc->rd_laddr.bt_psm < 0x1001 - || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm))) - return EADDRNOTAVAIL; - - LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) { - l2cap_sockaddr(rs->rs_l2cap, &addr); - - if (addr.bt_psm != dlc->rd_laddr.bt_psm) - continue; - - if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr)) - break; - } - - if (rs == NULL) { - rs = rfcomm_session_alloc(&rfcomm_session_listen, - &dlc->rd_laddr); - if (rs == NULL) - return ENOMEM; - - rs->rs_state = RFCOMM_SESSION_LISTEN; - - err = l2cap_listen(rs->rs_l2cap); - if (err) { - rfcomm_session_free(rs); - return err; - } - } - - if (dlc->rd_laddr.bt_channel == RFCOMM_CHANNEL_ANY) { - channel = RFCOMM_CHANNEL_MIN; - used = LIST_FIRST(&rs->rs_dlcs); - - while (used != NULL) { - if (used->rd_laddr.bt_channel == channel) { - if (channel++ == RFCOMM_CHANNEL_MAX) - return EADDRNOTAVAIL; - - used = LIST_FIRST(&rs->rs_dlcs); - } else { - used = LIST_NEXT(used, rd_next); - } - } - - dlc->rd_laddr.bt_channel = channel; - } - - dlc->rd_session = rs; - dlc->rd_state = RFCOMM_DLC_LISTEN; - LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next); - - return 0; -} - -/* - * rfcomm_send(dlc, mbuf) - * - * Output data on DLC. This is streamed data, so we add it - * to our buffer and start the DLC, which will assemble - * packets and send them if it can. - */ -int -rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m) -{ - - if (dlc->rd_txbuf != NULL) { - dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len; - m_cat(dlc->rd_txbuf, m); - } else { - dlc->rd_txbuf = m; - } - - if (dlc->rd_state == RFCOMM_DLC_OPEN) - rfcomm_dlc_start(dlc); - - return 0; -} - -/* - * rfcomm_rcvd(dlc, space) - * - * Indicate space now available in receive buffer - * - * This should be used to give an initial value of the receive buffer - * size when the DLC is attached and anytime data is cleared from the - * buffer after that. - */ -int -rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space) -{ - - KASSERT(dlc != NULL); - - dlc->rd_rxsize = space; - - /* - * if we are using credit based flow control, we may - * want to send some credits.. - */ - if (dlc->rd_state == RFCOMM_DLC_OPEN - && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC)) - rfcomm_dlc_start(dlc); - - return 0; -} - -/* - * rfcomm_setopt(dlc, option, m) - * - * set DLC options - */ -int -rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, struct mbuf *m) -{ - int mode, err = 0; - uint16_t mtu; - - switch (opt) { - case SO_RFCOMM_MTU: - if (m == NULL || m->m_len != sizeof(uint16_t)) - err = EINVAL; - else { - mtu = *mtod(m, uint16_t *); - if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX) - err = EINVAL; - else if (dlc->rd_state == RFCOMM_DLC_CLOSED) - dlc->rd_mtu = mtu; - else - err = EBUSY; - } - - break; - - case SO_RFCOMM_LM: - if (m == NULL || m->m_len != sizeof(int)) - err = EINVAL; - else { - mode = *mtod(m, int *); - mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | - RFCOMM_LM_AUTH); - - if (mode & RFCOMM_LM_SECURE) - mode |= RFCOMM_LM_ENCRYPT; - - if (mode & RFCOMM_LM_ENCRYPT) - mode |= RFCOMM_LM_AUTH; - - dlc->rd_mode = mode; - - if (dlc->rd_state == RFCOMM_DLC_OPEN) - err = rfcomm_dlc_setmode(dlc); - } - - break; - - default: - err = ENOPROTOOPT; - break; - } - return err; -} - -/* - * rfcomm_getopt(dlc, option, addr) - * - * get DLC options - */ -int -rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr) -{ - struct rfcomm_fc_info *fc; - - switch (opt) { - case SO_RFCOMM_MTU: - *(uint16_t *)addr = dlc->rd_mtu; - return sizeof(uint16_t); - - case SO_RFCOMM_FC_INFO: - fc = addr; - memset(fc, 0, sizeof(*fc)); - fc->lmodem = dlc->rd_lmodem; - fc->rmodem = dlc->rd_rmodem; - fc->tx_cred = max(dlc->rd_txcred, 0xff); - fc->rx_cred = max(dlc->rd_rxcred, 0xff); - if (dlc->rd_session - && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC)) - fc->cfc = 1; - - return sizeof(*fc); - - case SO_RFCOMM_LM: - *(int *)addr = dlc->rd_mode; - return sizeof(int); - - default: - break; - } - - return 0; -} diff --git a/sys/netbt/sco.h b/sys/netbt/sco.h deleted file mode 100644 index b93fee7f0f5..00000000000 --- a/sys/netbt/sco.h +++ /dev/null @@ -1,86 +0,0 @@ -/* $OpenBSD: sco.h,v 1.5 2009/11/21 13:05:32 guenther Exp $ */ -/* $NetBSD: sco.h,v 1.3 2008/08/06 15:01:24 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _NETBT_SCO_H_ -#define _NETBT_SCO_H_ - -#define SO_SCO_MTU 1 -#define SO_SCO_HANDLE 2 - -#ifdef _KERNEL -/* - * SCO protocol control block - */ -struct sco_pcb { - struct hci_link *sp_link; /* SCO link */ - unsigned int sp_flags; /* flags */ - bdaddr_t sp_laddr; /* local address */ - bdaddr_t sp_raddr; /* remote address */ - unsigned int sp_mtu; /* link MTU */ - int sp_pending; /* number of packets pending */ - - const struct btproto *sp_proto; /* upper layer protocol */ - void *sp_upper; /* upper layer argument */ - - LIST_ENTRY(sco_pcb) sp_next; -}; - -LIST_HEAD(sco_pcb_list, sco_pcb); -extern struct sco_pcb_list sco_pcb; - -/* sp_flags */ -#define SP_LISTENING (1<<0) /* is listening pcb */ - -/* sco_socket.c */ -struct socket; -extern int sco_sendspace; -extern int sco_recvspace; -int sco_usrreq(struct socket *, int, struct mbuf *, - struct mbuf *, struct mbuf *, struct proc *); -int sco_ctloutput(int, struct socket *, int, int, struct mbuf **); - -/* sco_upper.c */ -int sco_attach(struct sco_pcb **, const struct btproto *, void *); -int sco_bind(struct sco_pcb *, struct sockaddr_bt *); -int sco_sockaddr(struct sco_pcb *, struct sockaddr_bt *); -int sco_connect(struct sco_pcb *, struct sockaddr_bt *); -int sco_peeraddr(struct sco_pcb *, struct sockaddr_bt *); -int sco_disconnect(struct sco_pcb *, int); -int sco_detach(struct sco_pcb **); -int sco_listen(struct sco_pcb *); -int sco_send(struct sco_pcb *, struct mbuf *); -int sco_setopt(struct sco_pcb *, int, struct mbuf *); -int sco_getopt(struct sco_pcb *, int, void *); - -#endif /* _KERNEL */ - -#endif /* _NETBT_SCO_H_ */ diff --git a/sys/netbt/sco_socket.c b/sys/netbt/sco_socket.c deleted file mode 100644 index 94a674041a8..00000000000 --- a/sys/netbt/sco_socket.c +++ /dev/null @@ -1,378 +0,0 @@ -/* $OpenBSD: sco_socket.c,v 1.5 2012/12/05 23:20:23 deraadt Exp $ */ -/* $NetBSD: sco_socket.c,v 1.11 2008/08/06 15:01:24 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* load symbolic names */ -#ifdef BLUETOOTH_DEBUG -#define PRUREQUESTS -#define PRCOREQUESTS -#endif - -#include <sys/param.h> -#include <sys/domain.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/sco.h> - -/******************************************************************************* - * - * SCO SOCK_SEQPACKET sockets - low latency audio data - */ - -static void sco_connecting(void *); -static void sco_connected(void *); -static void sco_disconnected(void *, int); -static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); -static void sco_complete(void *, int); -static void sco_linkmode(void *, int); -static void sco_input(void *, struct mbuf *); - -static const struct btproto sco_proto = { - sco_connecting, - sco_connected, - sco_disconnected, - sco_newconn, - sco_complete, - sco_linkmode, - sco_input, -}; - -int sco_sendspace = 4096; -int sco_recvspace = 4096; - -/* - * User Request. - * up is socket - * m is either - * optional mbuf chain containing message - * ioctl command (PRU_CONTROL) - * nam is either - * optional mbuf chain containing an address - * ioctl data (PRU_CONTROL) - * optionally, protocol number (PRU_ATTACH) - * ctl is optional mbuf chain containing socket options - * l is pointer to process requesting action (if any) - * - * we are responsible for disposing of m and ctl if - * they are mbuf chains - */ -int -sco_usrreq(struct socket *up, int req, struct mbuf *m, - struct mbuf *nam, struct mbuf *ctl, struct proc *p) -{ - struct sco_pcb *pcb = (struct sco_pcb *)up->so_pcb; - struct sockaddr_bt *sa; - struct mbuf *m0; - int err = 0; - -#ifdef notyet /* XXX */ - DPRINTFN(2, "%s\n", prurequests[req]); -#endif - - switch(req) { - case PRU_CONTROL: - return EOPNOTSUPP; - -#ifdef notyet /* XXX */ - case PRU_PURGEIF: - return EOPNOTSUPP; -#endif - - case PRU_ATTACH: - /* XXX solock() and bt_lock fiddling in NetBSD */ - if (pcb) - return EINVAL; - err = soreserve(up, sco_sendspace, sco_recvspace); - if (err) - return err; - - return sco_attach((struct sco_pcb **)&up->so_pcb, - &sco_proto, up); - } - - /* anything after here *requires* a pcb */ - if (pcb == NULL) { - err = EINVAL; - goto release; - } - - switch(req) { - case PRU_DISCONNECT: - soisdisconnecting(up); - return sco_disconnect(pcb, up->so_linger); - - case PRU_ABORT: - sco_disconnect(pcb, 0); - soisdisconnected(up); - /* fall through to */ - case PRU_DETACH: - return sco_detach((struct sco_pcb **)&up->so_pcb); - - case PRU_BIND: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - - if (sa->bt_len != sizeof(struct sockaddr_bt)) - return EINVAL; - - if (sa->bt_family != AF_BLUETOOTH) - return EAFNOSUPPORT; - - return sco_bind(pcb, sa); - - case PRU_CONNECT: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - - if (sa->bt_len != sizeof(struct sockaddr_bt)) - return EINVAL; - - if (sa->bt_family != AF_BLUETOOTH) - return EAFNOSUPPORT; - - soisconnecting(up); - return sco_connect(pcb, sa); - - case PRU_PEERADDR: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - nam->m_len = sizeof(struct sockaddr_bt); - return sco_peeraddr(pcb, sa); - - case PRU_SOCKADDR: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - nam->m_len = sizeof(struct sockaddr_bt); - return sco_sockaddr(pcb, sa); - - case PRU_SHUTDOWN: - socantsendmore(up); - break; - - case PRU_SEND: - KASSERT(m != NULL); - if (m->m_pkthdr.len == 0) - break; - - if (m->m_pkthdr.len > pcb->sp_mtu) { - err = EMSGSIZE; - break; - } - - m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if (m0 == NULL) { - err = ENOMEM; - break; - } - - if (ctl) /* no use for that */ - m_freem(ctl); - - sbappendrecord(&up->so_snd, m); - return sco_send(pcb, m0); - - case PRU_SENSE: - return 0; /* (no sense - Doh!) */ - - case PRU_RCVD: - case PRU_RCVOOB: - return EOPNOTSUPP; /* (no release) */ - - case PRU_LISTEN: - return sco_listen(pcb); - - case PRU_ACCEPT: - KASSERT(nam != NULL); - sa = mtod(nam, struct sockaddr_bt *); - nam->m_len = sizeof(struct sockaddr_bt); - return sco_peeraddr(pcb, sa); - - case PRU_CONNECT2: - case PRU_SENDOOB: - case PRU_FASTTIMO: - case PRU_SLOWTIMO: - case PRU_PROTORCV: - case PRU_PROTOSEND: - err = EOPNOTSUPP; - break; - - default: - UNKNOWN(req); - err = EOPNOTSUPP; - break; - } - -release: - if (m) m_freem(m); - if (ctl) m_freem(ctl); - return err; -} - -/* - * get/set socket options - */ -int -sco_ctloutput(int req, struct socket *so, int level, - int optname, struct mbuf **opt) -{ - struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; - struct mbuf *m; - int err = 0; - -#ifdef notyet /* XXX */ - DPRINTFN(2, "req %s\n", prcorequests[req]); -#endif - - if (pcb == NULL) - return EINVAL; - - if (level != BTPROTO_SCO) { - err = EINVAL; - if (req == PRCO_SETOPT && *opt) - m_free(*opt); - } else switch(req) { - case PRCO_GETOPT: - m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = sco_getopt(pcb, optname, mtod(m, uint8_t *)); - if (m->m_len == 0) { - m_freem(m); - m = NULL; - err = ENOPROTOOPT; - } - *opt = m; - break; - - case PRCO_SETOPT: - m = *opt; - err = sco_setopt(pcb, optname, m); - m_freem(m); - break; - - default: - err = ENOPROTOOPT; - break; - } - - return err; -} - -/***************************************************************************** - * - * SCO Protocol socket callbacks - * - */ -static void -sco_connecting(void *arg) -{ - struct socket *so = arg; - - DPRINTF("Connecting\n"); - soisconnecting(so); -} - -static void -sco_connected(void *arg) -{ - struct socket *so = arg; - - DPRINTF("Connected\n"); - soisconnected(so); -} - -static void -sco_disconnected(void *arg, int err) -{ - struct socket *so = arg; - - DPRINTF("Disconnected (%d)\n", err); - - so->so_error = err; - soisdisconnected(so); -} - -static void * -sco_newconn(void *arg, struct sockaddr_bt *laddr, - struct sockaddr_bt *raddr) -{ - struct socket *so = arg; - - DPRINTF("New Connection\n"); - so = sonewconn(so, 0); - if (so == NULL) - return NULL; - - soisconnecting(so); - return so->so_pcb; -} - -static void -sco_complete(void *arg, int num) -{ - struct socket *so = arg; - - while (num-- > 0) - sbdroprecord(&so->so_snd); - - sowwakeup(so); -} - -static void -sco_linkmode(void *arg, int mode) -{ -} - -static void -sco_input(void *arg, struct mbuf *m) -{ - struct socket *so = arg; - - /* - * since this data is time sensitive, if the buffer - * is full we just dump data until the latest one - * will fit. - */ - - while (m->m_pkthdr.len > sbspace(&so->so_rcv)) - sbdroprecord(&so->so_rcv); - - DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); - - sbappendrecord(&so->so_rcv, m); - sorwakeup(so); -} diff --git a/sys/netbt/sco_upper.c b/sys/netbt/sco_upper.c deleted file mode 100644 index d30e4bbc63d..00000000000 --- a/sys/netbt/sco_upper.c +++ /dev/null @@ -1,354 +0,0 @@ -/* $OpenBSD: sco_upper.c,v 1.5 2012/12/05 23:20:23 deraadt Exp $ */ -/* $NetBSD: sco_upper.c,v 1.8 2008/08/06 15:01:24 plunky Exp $ */ - -/*- - * Copyright (c) 2006 Itronix Inc. - * All rights reserved. - * - * Written by Iain Hibbert for Itronix Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of Itronix Inc. may not be used to endorse - * or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/proc.h> -#include <sys/systm.h> - -#include <netbt/bluetooth.h> -#include <netbt/hci.h> -#include <netbt/sco.h> - -/**************************************************************************** - * - * SCO - Upper Protocol API - */ - -struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb); - -/* - * sco_attach(handle, proto, upper) - * - * Attach a new instance of SCO pcb to handle - */ -int -sco_attach(struct sco_pcb **handle, - const struct btproto *proto, void *upper) -{ - struct sco_pcb *pcb; - - KASSERT(handle != NULL); - KASSERT(proto != NULL); - KASSERT(upper != NULL); - - pcb = malloc(sizeof(*pcb), M_BLUETOOTH, M_NOWAIT | M_ZERO); - if (pcb == NULL) - return ENOMEM; - - pcb->sp_proto = proto; - pcb->sp_upper = upper; - - LIST_INSERT_HEAD(&sco_pcb, pcb, sp_next); - - *handle = pcb; - return 0; -} - -/* - * sco_bind(pcb, sockaddr) - * - * Bind SCO pcb to local address - */ -int -sco_bind(struct sco_pcb *pcb, struct sockaddr_bt *addr) -{ - - bdaddr_copy(&pcb->sp_laddr, &addr->bt_bdaddr); - return 0; -} - -/* - * sco_sockaddr(pcb, sockaddr) - * - * Copy local address of PCB to sockaddr - */ -int -sco_sockaddr(struct sco_pcb *pcb, struct sockaddr_bt *addr) -{ - - memset(addr, 0, sizeof(struct sockaddr_bt)); - addr->bt_len = sizeof(struct sockaddr_bt); - addr->bt_family = AF_BLUETOOTH; - bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_laddr); - return 0; -} - -/* - * sco_connect(pcb, sockaddr) - * - * Initiate a SCO connection to the destination address. - */ -int -sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest) -{ - hci_add_sco_con_cp cp; - struct hci_unit *unit; - struct hci_link *acl, *sco; - int err; - - if (pcb->sp_flags & SP_LISTENING) - return EINVAL; - - bdaddr_copy(&pcb->sp_raddr, &dest->bt_bdaddr); - - if (bdaddr_any(&pcb->sp_raddr)) - return EDESTADDRREQ; - - if (bdaddr_any(&pcb->sp_laddr)) { - err = hci_route_lookup(&pcb->sp_laddr, &pcb->sp_raddr); - if (err) - return err; - } - - unit = hci_unit_lookup(&pcb->sp_laddr); - if (unit == NULL) - return ENETDOWN; - - /* - * We must have an already open ACL connection before we open the SCO - * connection, and since SCO connections dont happen on their own we - * will not open one, the application wanting this should have opened - * it previously. - */ - acl = hci_link_lookup_bdaddr(unit, &pcb->sp_raddr, HCI_LINK_ACL); - if (acl == NULL || acl->hl_state != HCI_LINK_OPEN) - return EHOSTUNREACH; - - sco = hci_link_alloc(unit, &pcb->sp_raddr, HCI_LINK_SCO); - if (sco == NULL) - return ENOMEM; - - sco->hl_link = hci_acl_open(unit, &pcb->sp_raddr); - KASSERT(sco->hl_link == acl); - - cp.con_handle = htole16(acl->hl_handle); - cp.pkt_type = htole16(0x00e0); /* HV1, HV2, HV3 */ - err = hci_send_cmd(unit, HCI_CMD_ADD_SCO_CON, &cp, sizeof(cp)); - if (err) { - hci_link_free(sco, err); - return err; - } - - sco->hl_sco = pcb; - pcb->sp_link = sco; - - pcb->sp_mtu = unit->hci_max_sco_size; - return 0; -} - -/* - * sco_peeraddr(pcb, sockaddr) - * - * Copy remote address of SCO pcb to sockaddr - */ -int -sco_peeraddr(struct sco_pcb *pcb, struct sockaddr_bt *addr) -{ - - memset(addr, 0, sizeof(struct sockaddr_bt)); - addr->bt_len = sizeof(struct sockaddr_bt); - addr->bt_family = AF_BLUETOOTH; - bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_raddr); - return 0; -} - -/* - * sco_disconnect(pcb, linger) - * - * Initiate disconnection of connected SCO pcb - */ -int -sco_disconnect(struct sco_pcb *pcb, int linger) -{ - hci_discon_cp cp; - struct hci_link *sco; - int err; - - sco = pcb->sp_link; - if (sco == NULL) - return EINVAL; - - cp.con_handle = htole16(sco->hl_handle); - cp.reason = 0x13; /* "Remote User Terminated Connection" */ - - err = hci_send_cmd(sco->hl_unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp)); - if (err || linger == 0) { - sco->hl_sco = NULL; - pcb->sp_link = NULL; - hci_link_free(sco, err); - } - - return err; -} - -/* - * sco_detach(handle) - * - * Detach SCO pcb from handle and clear up - */ -int -sco_detach(struct sco_pcb **handle) -{ - struct sco_pcb *pcb; - - KASSERT(handle != NULL); - pcb = *handle; - *handle = NULL; - - if (pcb == NULL) - return EINVAL; - - if (pcb->sp_link != NULL) { - sco_disconnect(pcb, 0); - pcb->sp_link = NULL; - } - - LIST_REMOVE(pcb, sp_next); - free(pcb, M_BLUETOOTH); - return 0; -} - -/* - * sco_listen(pcb) - * - * Mark pcb as a listener. - */ -int -sco_listen(struct sco_pcb *pcb) -{ - - if (pcb->sp_link != NULL) - return EINVAL; - - pcb->sp_flags |= SP_LISTENING; - return 0; -} - -/* - * sco_send(pcb, mbuf) - * - * Send data on SCO pcb. - * - * Gross hackage, we just output the packet directly onto the unit queue. - * This will work fine for one channel per unit, but for more channels it - * really needs fixing. We set the context so that when the packet is sent, - * we can drop a record from the socket buffer. - */ -int -sco_send(struct sco_pcb *pcb, struct mbuf *m) -{ - hci_scodata_hdr_t *hdr; - int plen; - - if (pcb->sp_link == NULL) { - m_freem(m); - return EINVAL; - } - - plen = m->m_pkthdr.len; - DPRINTFN(10, "%d bytes\n", plen); - - /* - * This is a temporary limitation, as USB devices cannot - * handle SCO packet sizes that are not an integer number - * of Isochronous frames. See ubt(4) - */ - if (plen != pcb->sp_mtu) { - m_freem(m); - return EMSGSIZE; - } - - M_PREPEND(m, sizeof(hci_scodata_hdr_t), M_DONTWAIT); - if (m == NULL) - return ENOMEM; - - hdr = mtod(m, hci_scodata_hdr_t *); - hdr->type = HCI_SCO_DATA_PKT; - hdr->con_handle = htole16(pcb->sp_link->hl_handle); - hdr->length = plen; - - pcb->sp_pending++; - M_SETCTX(m, pcb->sp_link); - hci_output_sco(pcb->sp_link->hl_unit, m); - - return 0; -} - -/* - * sco_setopt(pcb, option, m) - * - * Set SCO pcb options - */ -int -sco_setopt(struct sco_pcb *pcb, int opt, struct mbuf *m) -{ - int err = 0; - - switch (opt) { - default: - err = ENOPROTOOPT; - break; - } - - return err; -} - -/* - * sco_getopt(pcb, option, addr) - * - * Get SCO pcb options - */ -int -sco_getopt(struct sco_pcb *pcb, int opt, void *addr) -{ - - switch (opt) { - case SO_SCO_MTU: - *(uint16_t *)addr = pcb->sp_mtu; - return sizeof(uint16_t); - - case SO_SCO_HANDLE: - if (pcb->sp_link) { - *(uint16_t *)addr = pcb->sp_link->hl_handle; - return sizeof(uint16_t); - } - break; - - default: - break; - } - return 0; -} |