Commit 4438669e authored by David S. Miller's avatar David S. Miller

Merge tag 'for-net-next-2021-04-08' of...

Merge tag 'for-net-next-2021-04-08' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Luiz Augusto von Dentz says:

====================
bluetooth-next pull request for net-next:

 - Proper support for BCM4330 and BMC4334
 - Various improvements for firmware download of Intel controllers
 - Update management interface revision to 20
 - Support for AOSP HCI vendor commands
 - Initial Virtio support
====================
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4914a4f6 a61d6718
Broadcom Bluetooth Chips
---------------------
This documents the binding structure and common properties for serial
attached Broadcom devices.
Serial attached Broadcom devices shall be a child node of the host UART
device the slave device is attached to.
Required properties:
- compatible: should contain one of the following:
* "brcm,bcm20702a1"
* "brcm,bcm4329-bt"
* "brcm,bcm4330-bt"
* "brcm,bcm43438-bt"
* "brcm,bcm4345c5"
* "brcm,bcm43540-bt"
* "brcm,bcm4335a0"
Optional properties:
- max-speed: see Documentation/devicetree/bindings/serial/serial.yaml
- shutdown-gpios: GPIO specifier, used to enable the BT module
- device-wakeup-gpios: GPIO specifier, used to wakeup the controller
- host-wakeup-gpios: GPIO specifier, used to wakeup the host processor.
deprecated, replaced by interrupts and
"host-wakeup" interrupt-names
- clocks: 1 or 2 clocks as defined in clock-names below, in that order
- clock-names: names for clock inputs, matching the clocks given
- "extclk": deprecated, replaced by "txco"
- "txco": external reference clock (not a standalone crystal)
- "lpo": external low power 32.768 kHz clock
- vbat-supply: phandle to regulator supply for VBAT
- vddio-supply: phandle to regulator supply for VDDIO
- brcm,bt-pcm-int-params: configure PCM parameters via a 5-byte array
- sco-routing: 0 = PCM, 1 = Transport, 2 = Codec, 3 = I2S
- pcm-interface-rate: 128KBps, 256KBps, 512KBps, 1024KBps, 2048KBps
- pcm-frame-type: short, long
- pcm-sync-mode: slave, master
- pcm-clock-mode: slave, master
- interrupts: must be one, used to wakeup the host processor
- interrupt-names: must be "host-wakeup"
Example:
&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&uart2_pins>;
bluetooth {
compatible = "brcm,bcm43438-bt";
max-speed = <921600>;
brcm,bt-pcm-int-params = [01 02 00 01 01];
};
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/broadcom-bluetooth.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom Bluetooth Chips
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
description:
This binding describes Broadcom UART-attached bluetooth chips.
properties:
compatible:
enum:
- brcm,bcm20702a1
- brcm,bcm4329-bt
- brcm,bcm4330-bt
- brcm,bcm4334-bt
- brcm,bcm43438-bt
- brcm,bcm4345c5
- brcm,bcm43540-bt
- brcm,bcm4335a0
shutdown-gpios:
maxItems: 1
description: GPIO specifier for the line BT_REG_ON used to
power on the BT module
reset-gpios:
maxItems: 1
description: GPIO specifier for the line BT_RST_N used to
reset the BT module. This should be marked as
GPIO_ACTIVE_LOW.
device-wakeup-gpios:
maxItems: 1
description: GPIO specifier for the line BT_WAKE used to
wakeup the controller. This is using the BT_GPIO_0
pin on the chip when in use.
host-wakeup-gpios:
maxItems: 1
deprecated: true
description: GPIO specifier for the line HOST_WAKE used
to wakeup the host processor. This is using he BT_GPIO_1
pin on the chip when in use. This is deprecated and replaced
by interrupts and "host-wakeup" interrupt-names
clocks:
maxItems: 2
description: 1 or 2 clocks as defined in clock-names below,
in that order
clock-names:
description: Names of the 1 to 2 supplied clocks
items:
- const: txco
- const: lpo
- const: extclk
vbat-supply:
description: phandle to regulator supply for VBAT
vddio-supply:
description: phandle to regulator supply for VDDIO
brcm,bt-pcm-int-params:
$ref: /schemas/types.yaml#/definitions/uint8-array
minItems: 5
maxItems: 5
description: |-
configure PCM parameters via a 5-byte array:
sco-routing: 0 = PCM, 1 = Transport, 2 = Codec, 3 = I2S
pcm-interface-rate: 128KBps, 256KBps, 512KBps, 1024KBps, 2048KBps
pcm-frame-type: short, long
pcm-sync-mode: slave, master
pcm-clock-mode: slave, master
interrupts:
items:
- description: Handle to the line HOST_WAKE used to wake
up the host processor. This uses the BT_GPIO_1 pin on
the chip when in use.
interrupt-names:
items:
- const: host-wakeup
max-speed: true
current-speed: true
required:
- compatible
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
uart {
uart-has-rtscts;
bluetooth {
compatible = "brcm,bcm4330-bt";
max-speed = <921600>;
brcm,bt-pcm-int-params = [01 02 00 01 01];
shutdown-gpios = <&gpio 30 GPIO_ACTIVE_HIGH>;
device-wakeup-gpios = <&gpio 7 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio 9 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio>;
interrupts = <8 IRQ_TYPE_EDGE_FALLING>;
};
};
......@@ -91,7 +91,7 @@ examples:
bluetooth {
compatible = "brcm,bcm4330-bt";
reset-gpios = <&gpf 8 GPIO_ACTIVE_HIGH>;
vcc-supply = <&wlan0_power>;
vbat-supply = <&wlan0_power>;
device-wakeup-gpios = <&gpf 5 GPIO_ACTIVE_HIGH>;
host-wakeup-gpios = <&gpf 6 GPIO_ACTIVE_HIGH>;
shutdown-gpios = <&gpf 4 GPIO_ACTIVE_LOW>;
......
......@@ -425,4 +425,14 @@ config BT_HCIRSI
Say Y here to compile support for HCI over Redpine into the
kernel or say M to compile as a module.
config BT_VIRTIO
tristate "Virtio Bluetooth driver"
depends on VIRTIO
help
Virtio Bluetooth support driver.
This driver supports Virtio Bluetooth devices.
Say Y here to compile support for HCI over Virtio into the
kernel or say M to compile as a module.
endmenu
......@@ -26,6 +26,8 @@ obj-$(CONFIG_BT_BCM) += btbcm.o
obj-$(CONFIG_BT_RTL) += btrtl.o
obj-$(CONFIG_BT_QCA) += btqca.o
obj-$(CONFIG_BT_VIRTIO) += virtio_bt.o
obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o
obj-$(CONFIG_BT_HCIRSI) += btrsi.o
......
This diff is collapsed.
......@@ -148,8 +148,8 @@ int btintel_set_diag(struct hci_dev *hdev, bool enable);
int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable);
void btintel_hw_error(struct hci_dev *hdev, u8 code);
void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version);
int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
int btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version);
int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
const void *param);
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name);
......@@ -163,9 +163,10 @@ struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param);
int btintel_read_boot_params(struct hci_dev *hdev,
struct intel_boot_params *params);
int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
u32 *boot_param);
int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
const struct firmware *fw, u32 *boot_param);
int btintel_download_firmware_newgen(struct hci_dev *hdev,
struct intel_version_tlv *ver,
const struct firmware *fw,
u32 *boot_param, u8 hw_variant,
u8 sbe_type);
......@@ -210,14 +211,16 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
{
}
static inline void btintel_version_info(struct hci_dev *hdev,
struct intel_version *ver)
static inline int btintel_version_info(struct hci_dev *hdev,
struct intel_version *ver)
{
return -EOPNOTSUPP;
}
static inline void btintel_version_info_tlv(struct hci_dev *hdev,
struct intel_version_tlv *version)
static inline int btintel_version_info_tlv(struct hci_dev *hdev,
struct intel_version_tlv *version)
{
return -EOPNOTSUPP;
}
static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type,
......
This diff is collapsed.
......@@ -68,6 +68,8 @@ struct bcm_device_data {
* deassert = Bluetooth device may sleep when sleep criteria are met
* @shutdown: BT_REG_ON pin,
* power up or power down Bluetooth device internal regulators
* @reset: BT_RST_N pin,
* active low resets the Bluetooth logic core
* @set_device_wakeup: callback to toggle BT_WAKE pin
* either by accessing @device_wakeup or by calling @btlp
* @set_shutdown: callback to toggle BT_REG_ON pin
......@@ -101,6 +103,7 @@ struct bcm_device {
const char *name;
struct gpio_desc *device_wakeup;
struct gpio_desc *shutdown;
struct gpio_desc *reset;
int (*set_device_wakeup)(struct bcm_device *, bool);
int (*set_shutdown)(struct bcm_device *, bool);
#ifdef CONFIG_ACPI
......@@ -985,6 +988,15 @@ static int bcm_gpio_set_device_wakeup(struct bcm_device *dev, bool awake)
static int bcm_gpio_set_shutdown(struct bcm_device *dev, bool powered)
{
gpiod_set_value_cansleep(dev->shutdown, powered);
if (dev->reset)
/*
* The reset line is asserted on powerdown and deasserted
* on poweron so the inverse of powered is used. Notice
* that the GPIO line BT_RST_N needs to be specified as
* active low in the device tree or similar system
* description.
*/
gpiod_set_value_cansleep(dev->reset, !powered);
return 0;
}
......@@ -1050,6 +1062,11 @@ static int bcm_get_resources(struct bcm_device *dev)
if (IS_ERR(dev->shutdown))
return PTR_ERR(dev->shutdown);
dev->reset = devm_gpiod_get_optional(dev->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(dev->reset))
return PTR_ERR(dev->reset);
dev->set_device_wakeup = bcm_gpio_set_device_wakeup;
dev->set_shutdown = bcm_gpio_set_shutdown;
......@@ -1482,6 +1499,8 @@ static struct bcm_device_data bcm43438_device_data = {
static const struct of_device_id bcm_bluetooth_of_match[] = {
{ .compatible = "brcm,bcm20702a1" },
{ .compatible = "brcm,bcm4329-bt" },
{ .compatible = "brcm,bcm4330-bt" },
{ .compatible = "brcm,bcm4334-bt" },
{ .compatible = "brcm,bcm4345c5" },
{ .compatible = "brcm,bcm4330-bt" },
{ .compatible = "brcm,bcm43438-bt", .data = &bcm43438_device_data },
......
......@@ -735,7 +735,7 @@ static int intel_setup(struct hci_uart *hu)
set_bit(STATE_DOWNLOADING, &intel->flags);
/* Start firmware downloading and get boot parameter */
err = btintel_download_firmware(hdev, fw, &boot_param);
err = btintel_download_firmware(hdev, &ver, fw, &boot_param);
if (err < 0)
goto done;
......@@ -784,7 +784,10 @@ static int intel_setup(struct hci_uart *hu)
done:
release_firmware(fw);
if (err < 0)
/* Check if there was an error and if is not -EALREADY which means the
* firmware has already been loaded.
*/
if (err < 0 && err != -EALREADY)
return err;
/* We need to restore the default speed before Intel reset */
......
......@@ -1066,7 +1066,7 @@ static void qca_controller_memdump(struct work_struct *work)
* packets in the buffer.
*/
/* For QCA6390, controller does not lost packets but
* sequence number field of packat sometimes has error
* sequence number field of packet sometimes has error
* bits, so skip this checking for missing packet.
*/
while ((seq_no > qca_memdump->current_seq_no + 1) &&
......@@ -1571,6 +1571,20 @@ static void qca_cmd_timeout(struct hci_dev *hdev)
mutex_unlock(&qca->hci_memdump_lock);
}
static bool qca_prevent_wake(struct hci_dev *hdev)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
bool wakeup;
/* UART driver handles the interrupt from BT SoC.So we need to use
* device handle of UART driver to get the status of device may wakeup.
*/
wakeup = device_may_wakeup(hu->serdev->ctrl->dev.parent);
bt_dev_dbg(hu->hdev, "wakeup status : %d", wakeup);
return !wakeup;
}
static int qca_wcn3990_init(struct hci_uart *hu)
{
struct qca_serdev *qcadev;
......@@ -1721,6 +1735,7 @@ static int qca_setup(struct hci_uart *hu)
qca_debugfs_init(hdev);
hu->hdev->hw_error = qca_hw_error;
hu->hdev->cmd_timeout = qca_cmd_timeout;
hu->hdev->prevent_wake = qca_prevent_wake;
} else if (ret == -ENOENT) {
/* No patch/nvm-config found, run with original fw/config */
set_bit(QCA_ROM_FW, &qca->flags);
......
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_config.h>
#include <linux/skbuff.h>
#include <uapi/linux/virtio_ids.h>
#include <uapi/linux/virtio_bt.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#define VERSION "0.1"
enum {
VIRTBT_VQ_TX,
VIRTBT_VQ_RX,
VIRTBT_NUM_VQS,
};
struct virtio_bluetooth {
struct virtio_device *vdev;
struct virtqueue *vqs[VIRTBT_NUM_VQS];
struct work_struct rx;
struct hci_dev *hdev;
};
static int virtbt_add_inbuf(struct virtio_bluetooth *vbt)
{
struct virtqueue *vq = vbt->vqs[VIRTBT_VQ_RX];
struct scatterlist sg[1];
struct sk_buff *skb;
int err;
skb = alloc_skb(1000, GFP_KERNEL);
sg_init_one(sg, skb->data, 1000);
err = virtqueue_add_inbuf(vq, sg, 1, skb, GFP_KERNEL);
if (err < 0) {
kfree_skb(skb);
return err;
}
return 0;
}
static int virtbt_open(struct hci_dev *hdev)
{
struct virtio_bluetooth *vbt = hci_get_drvdata(hdev);
if (virtbt_add_inbuf(vbt) < 0)
return -EIO;
virtqueue_kick(vbt->vqs[VIRTBT_VQ_RX]);
return 0;
}
static int virtbt_close(struct hci_dev *hdev)
{
struct virtio_bluetooth *vbt = hci_get_drvdata(hdev);
int i;
cancel_work_sync(&vbt->rx);
for (i = 0; i < ARRAY_SIZE(vbt->vqs); i++) {
struct virtqueue *vq = vbt->vqs[i];
struct sk_buff *skb;
while ((skb = virtqueue_detach_unused_buf(vq)))
kfree_skb(skb);
}
return 0;
}
static int virtbt_flush(struct hci_dev *hdev)
{
return 0;
}
static int virtbt_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
struct virtio_bluetooth *vbt = hci_get_drvdata(hdev);
struct scatterlist sg[1];
int err;
memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
sg_init_one(sg, skb->data, skb->len);
err = virtqueue_add_outbuf(vbt->vqs[VIRTBT_VQ_TX], sg, 1, skb,
GFP_KERNEL);
if (err) {
kfree_skb(skb);
return err;
}
virtqueue_kick(vbt->vqs[VIRTBT_VQ_TX]);
return 0;
}
static int virtbt_setup_zephyr(struct hci_dev *hdev)
{
struct sk_buff *skb;
/* Read Build Information */
skb = __hci_cmd_sync(hdev, 0xfc08, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
bt_dev_info(hdev, "%s", (char *)(skb->data + 1));
hci_set_fw_info(hdev, "%s", skb->data + 1);
kfree_skb(skb);
return 0;
}
static int virtbt_set_bdaddr_zephyr(struct hci_dev *hdev,
const bdaddr_t *bdaddr)
{
struct sk_buff *skb;
/* Write BD_ADDR */
skb = __hci_cmd_sync(hdev, 0xfc06, 6, bdaddr, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
return 0;
}
static int virtbt_setup_intel(struct hci_dev *hdev)
{
struct sk_buff *skb;
/* Intel Read Version */
skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
return 0;
}
static int virtbt_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{
struct sk_buff *skb;
/* Intel Write BD Address */
skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
return 0;
}
static int virtbt_setup_realtek(struct hci_dev *hdev)
{
struct sk_buff *skb;
/* Read ROM Version */
skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
bt_dev_info(hdev, "ROM version %u", *((__u8 *) (skb->data + 1)));
kfree_skb(skb);
return 0;
}
static int virtbt_shutdown_generic(struct hci_dev *hdev)
{
struct sk_buff *skb;
/* Reset */
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
return 0;
}
static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
{
__u8 pkt_type;
pkt_type = *((__u8 *) skb->data);
skb_pull(skb, 1);
switch (pkt_type) {
case HCI_EVENT_PKT:
case HCI_ACLDATA_PKT:
case HCI_SCODATA_PKT:
case HCI_ISODATA_PKT:
hci_skb_pkt_type(skb) = pkt_type;
hci_recv_frame(vbt->hdev, skb);
break;
}
}
static void virtbt_rx_work(struct work_struct *work)
{
struct virtio_bluetooth *vbt = container_of(work,
struct virtio_bluetooth, rx);
struct sk_buff *skb;
unsigned int len;
skb = virtqueue_get_buf(vbt->vqs[VIRTBT_VQ_RX], &len);
if (!skb)
return;
skb->len = len;
virtbt_rx_handle(vbt, skb);
if (virtbt_add_inbuf(vbt) < 0)
return;
virtqueue_kick(vbt->vqs[VIRTBT_VQ_RX]);
}
static void virtbt_tx_done(struct virtqueue *vq)
{
struct sk_buff *skb;
unsigned int len;
while ((skb = virtqueue_get_buf(vq, &len)))
kfree_skb(skb);
}
static void virtbt_rx_done(struct virtqueue *vq)
{
struct virtio_bluetooth *vbt = vq->vdev->priv;
schedule_work(&vbt->rx);
}
static int virtbt_probe(struct virtio_device *vdev)
{
vq_callback_t *callbacks[VIRTBT_NUM_VQS] = {
[VIRTBT_VQ_TX] = virtbt_tx_done,
[VIRTBT_VQ_RX] = virtbt_rx_done,
};
const char *names[VIRTBT_NUM_VQS] = {
[VIRTBT_VQ_TX] = "tx",
[VIRTBT_VQ_RX] = "rx",
};
struct virtio_bluetooth *vbt;
struct hci_dev *hdev;
int err;
__u8 type;
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
return -ENODEV;
type = virtio_cread8(vdev, offsetof(struct virtio_bt_config, type));
switch (type) {
case VIRTIO_BT_CONFIG_TYPE_PRIMARY:
case VIRTIO_BT_CONFIG_TYPE_AMP:
break;
default:
return -EINVAL;
}
vbt = kzalloc(sizeof(*vbt), GFP_KERNEL);
if (!vbt)
return -ENOMEM;
vdev->priv = vbt;
vbt->vdev = vdev;
INIT_WORK(&vbt->rx, virtbt_rx_work);
err = virtio_find_vqs(vdev, VIRTBT_NUM_VQS, vbt->vqs, callbacks,
names, NULL);
if (err)
return err;
hdev = hci_alloc_dev();
if (!hdev) {
err = -ENOMEM;
goto failed;
}
vbt->hdev = hdev;
hdev->bus = HCI_VIRTIO;
hdev->dev_type = type;
hci_set_drvdata(hdev, vbt);
hdev->open = virtbt_open;
hdev->close = virtbt_close;
hdev->flush = virtbt_flush;
hdev->send = virtbt_send_frame;
if (virtio_has_feature(vdev, VIRTIO_BT_F_VND_HCI)) {
__u16 vendor;
virtio_cread(vdev, struct virtio_bt_config, vendor, &vendor);
switch (vendor) {
case VIRTIO_BT_CONFIG_VENDOR_ZEPHYR:
hdev->manufacturer = 1521;
hdev->setup = virtbt_setup_zephyr;
hdev->shutdown = virtbt_shutdown_generic;
hdev->set_bdaddr = virtbt_set_bdaddr_zephyr;
break;
case VIRTIO_BT_CONFIG_VENDOR_INTEL:
hdev->manufacturer = 2;
hdev->setup = virtbt_setup_intel;
hdev->shutdown = virtbt_shutdown_generic;
hdev->set_bdaddr = virtbt_set_bdaddr_intel;
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
break;
case VIRTIO_BT_CONFIG_VENDOR_REALTEK:
hdev->manufacturer = 93;
hdev->setup = virtbt_setup_realtek;
hdev->shutdown = virtbt_shutdown_generic;
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
break;
}
}
if (virtio_has_feature(vdev, VIRTIO_BT_F_MSFT_EXT)) {
__u16 msft_opcode;
virtio_cread(vdev, struct virtio_bt_config,
msft_opcode, &msft_opcode);
hci_set_msft_opcode(hdev, msft_opcode);
}
if (virtio_has_feature(vdev, VIRTIO_BT_F_AOSP_EXT))
hci_set_aosp_capable(hdev);
if (hci_register_dev(hdev) < 0) {
hci_free_dev(hdev);
err = -EBUSY;
goto failed;
}
return 0;
failed:
vdev->config->del_vqs(vdev);
return err;
}
static void virtbt_remove(struct virtio_device *vdev)
{
struct virtio_bluetooth *vbt = vdev->priv;
struct hci_dev *hdev = vbt->hdev;
hci_unregister_dev(hdev);
vdev->config->reset(vdev);
hci_free_dev(hdev);
vbt->hdev = NULL;
vdev->config->del_vqs(vdev);
kfree(vbt);
}
static struct virtio_device_id virtbt_table[] = {
{ VIRTIO_ID_BT, VIRTIO_DEV_ANY_ID },
{ 0 },
};
MODULE_DEVICE_TABLE(virtio, virtbt_table);
static const unsigned int virtbt_features[] = {
VIRTIO_BT_F_VND_HCI,
VIRTIO_BT_F_MSFT_EXT,
VIRTIO_BT_F_AOSP_EXT,
};
static struct virtio_driver virtbt_driver = {
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.feature_table = virtbt_features,
.feature_table_size = ARRAY_SIZE(virtbt_features),
.id_table = virtbt_table,
.probe = virtbt_probe,
.remove = virtbt_remove,
};
module_virtio_driver(virtbt_driver);
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Generic Bluetooth VIRTIO driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
......@@ -320,6 +320,7 @@ enum {
HCI_BREDR_ENABLED,
HCI_LE_SCAN_INTERRUPTED,
HCI_WIDEBAND_SPEECH_ENABLED,
HCI_EVENT_FILTER_CONFIGURED,
HCI_DUT_MODE,
HCI_VENDOR_DIAG,
......
......@@ -584,6 +584,11 @@ struct hci_dev {
#if IS_ENABLED(CONFIG_BT_MSFTEXT)
__u16 msft_opcode;
void *msft_data;
bool msft_curve_validity;
#endif
#if IS_ENABLED(CONFIG_BT_AOSPEXT)
bool aosp_capable;
#endif
int (*open)(struct hci_dev *hdev);
......@@ -704,6 +709,7 @@ struct hci_chan {
struct sk_buff_head data_q;
unsigned int sent;
__u8 state;
bool amp;
};
struct hci_conn_params {
......@@ -1238,6 +1244,13 @@ static inline void hci_set_msft_opcode(struct hci_dev *hdev, __u16 opcode)
#endif
}
static inline void hci_set_aosp_capable(struct hci_dev *hdev)
{
#if IS_ENABLED(CONFIG_BT_AOSPEXT)
hdev->aosp_capable = true;
#endif
}
int hci_dev_open(__u16 dev);
int hci_dev_close(__u16 dev);
int hci_dev_do_close(struct hci_dev *hdev);
......@@ -1742,8 +1755,8 @@ void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c);
#define DISCOV_INTERLEAVED_INQUIRY_LEN 0x04
#define DISCOV_BREDR_INQUIRY_LEN 0x08
#define DISCOV_LE_RESTART_DELAY msecs_to_jiffies(200) /* msec */
#define DISCOV_LE_FAST_ADV_INT_MIN 100 /* msec */
#define DISCOV_LE_FAST_ADV_INT_MAX 150 /* msec */
#define DISCOV_LE_FAST_ADV_INT_MIN 0x00A0 /* 100 msec */
#define DISCOV_LE_FAST_ADV_INT_MAX 0x00F0 /* 150 msec */
void mgmt_fill_version_info(void *ver);
int mgmt_new_settings(struct hci_dev *hdev);
......
......@@ -494,6 +494,7 @@ struct l2cap_le_credits {
#define L2CAP_ECRED_MIN_MTU 64
#define L2CAP_ECRED_MIN_MPS 64
#define L2CAP_ECRED_MAX_CID 5
struct l2cap_ecred_conn_req {
__le16 psm;
......
......@@ -578,6 +578,7 @@ struct mgmt_rp_add_advertising {
#define MGMT_ADV_PARAM_TIMEOUT BIT(13)
#define MGMT_ADV_PARAM_INTERVALS BIT(14)
#define MGMT_ADV_PARAM_TX_POWER BIT(15)
#define MGMT_ADV_PARAM_SCAN_RSP BIT(16)
#define MGMT_ADV_FLAG_SEC_MASK (MGMT_ADV_FLAG_SEC_1M | MGMT_ADV_FLAG_SEC_2M | \
MGMT_ADV_FLAG_SEC_CODED)
......
/* SPDX-License-Identifier: BSD-3-Clause */
#ifndef _UAPI_LINUX_VIRTIO_BT_H
#define _UAPI_LINUX_VIRTIO_BT_H
#include <linux/virtio_types.h>
/* Feature bits */
#define VIRTIO_BT_F_VND_HCI 0 /* Indicates vendor command support */
#define VIRTIO_BT_F_MSFT_EXT 1 /* Indicates MSFT vendor support */
#define VIRTIO_BT_F_AOSP_EXT 2 /* Indicates AOSP vendor support */
enum virtio_bt_config_type {
VIRTIO_BT_CONFIG_TYPE_PRIMARY = 0,
VIRTIO_BT_CONFIG_TYPE_AMP = 1,
};
enum virtio_bt_config_vendor {
VIRTIO_BT_CONFIG_VENDOR_NONE = 0,
VIRTIO_BT_CONFIG_VENDOR_ZEPHYR = 1,
VIRTIO_BT_CONFIG_VENDOR_INTEL = 2,
VIRTIO_BT_CONFIG_VENDOR_REALTEK = 3,
};
struct virtio_bt_config {
__u8 type;
__u16 vendor;
__u16 msft_opcode;
} __attribute__((packed));
#endif /* _UAPI_LINUX_VIRTIO_BT_H */
......@@ -53,6 +53,7 @@
#define VIRTIO_ID_MEM 24 /* virtio mem */
#define VIRTIO_ID_FS 26 /* virtio filesystem */
#define VIRTIO_ID_PMEM 27 /* virtio pmem */
#define VIRTIO_ID_BT 28 /* virtio bluetooth */
#define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
#endif /* _LINUX_VIRTIO_IDS_H */
......@@ -205,8 +205,7 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_btle_dev *dev,
}
}
/* use the neighbour cache for matching addresses assigned by SLAAC
*/
/* use the neighbour cache for matching addresses assigned by SLAAC */
neigh = __ipv6_neigh_lookup(dev->netdev, nexthop);
if (neigh) {
list_for_each_entry_rcu(peer, &dev->peers, list) {
......@@ -841,8 +840,6 @@ static void chan_close_cb(struct l2cap_chan *chan)
} else {
spin_unlock(&devices_lock);
}
return;
}
static void chan_state_change_cb(struct l2cap_chan *chan, int state, int err)
......
......@@ -99,6 +99,13 @@ config BT_MSFTEXT
This options enables support for the Microsoft defined HCI
vendor extensions.
config BT_AOSPEXT
bool "Enable Android Open Source Project extensions"
depends on BT
help
This options enables support for the Android Open Source
Project defined HCI vendor extensions.
config BT_DEBUGFS
bool "Export Bluetooth internals in debugfs"
depends on BT && DEBUG_FS
......
......@@ -20,5 +20,6 @@ bluetooth-$(CONFIG_BT_BREDR) += sco.o
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
bluetooth-$(CONFIG_BT_LEDS) += leds.o
bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o
bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o
bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021 Intel Corporation
*/
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "aosp.h"
void aosp_do_open(struct hci_dev *hdev)
{
struct sk_buff *skb;
if (!hdev->aosp_capable)
return;
bt_dev_dbg(hdev, "Initialize AOSP extension");
/* LE Get Vendor Capabilities Command */
skb = __hci_cmd_sync(hdev, hci_opcode_pack(0x3f, 0x153), 0, NULL,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb))
return;
kfree_skb(skb);
}
void aosp_do_close(struct hci_dev *hdev)
{
if (!hdev->aosp_capable)
return;
bt_dev_dbg(hdev, "Cleanup of AOSP extension");
}
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021 Intel Corporation
*/
#if IS_ENABLED(CONFIG_BT_AOSPEXT)
void aosp_do_open(struct hci_dev *hdev);
void aosp_do_close(struct hci_dev *hdev);
#else
static inline void aosp_do_open(struct hci_dev *hdev) {}
static inline void aosp_do_close(struct hci_dev *hdev) {}
#endif
......@@ -25,6 +25,6 @@
int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 pair_public_key[64],
u8 secret[32]);
int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 *private_key);
int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 private_key[32]);
int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64]);
int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64]);
......@@ -772,6 +772,16 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
hci_conn_del(conn);
/* The suspend notifier is waiting for all devices to disconnect and an
* LE connect cancel will result in an hci_le_conn_failed. Once the last
* connection is deleted, we should also wake the suspend queue to
* complete suspend operations.
*/
if (list_empty(&hdev->conn_hash.list) &&
test_and_clear_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks)) {
wake_up(&hdev->suspend_wait_q);
}
/* Since we may have temporarily stopped the background scanning in
* favor of connection establishment, we should restart it.
*/
......@@ -1830,8 +1840,6 @@ u32 hci_conn_get_phy(struct hci_conn *conn)
{
u32 phys = 0;
hci_dev_lock(conn->hdev);
/* BLUETOOTH CORE SPECIFICATION Version 5.2 | Vol 2, Part B page 471:
* Table 6.2: Packets defined for synchronous, asynchronous, and
* CSB logical transport types.
......@@ -1928,7 +1936,5 @@ u32 hci_conn_get_phy(struct hci_conn *conn)
break;
}
hci_dev_unlock(conn->hdev);
return phys;
}
......@@ -44,6 +44,7 @@
#include "smp.h"
#include "leds.h"
#include "msft.h"
#include "aosp.h"
static void hci_rx_work(struct work_struct *work);
static void hci_cmd_work(struct work_struct *work);
......@@ -1586,6 +1587,7 @@ static int hci_dev_do_open(struct hci_dev *hdev)
ret = hdev->set_diag(hdev, true);
msft_do_open(hdev);
aosp_do_open(hdev);
clear_bit(HCI_INIT, &hdev->flags);
......@@ -1782,6 +1784,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
hci_sock_dev_event(hdev, HCI_DEV_DOWN);
aosp_do_close(hdev);
msft_do_close(hdev);
if (hdev->flush)
......@@ -3760,6 +3763,8 @@ struct hci_dev *hci_alloc_dev(void)
hdev->le_scan_window_suspend = 0x0012;
hdev->le_scan_int_discovery = DISCOV_LE_SCAN_INT;
hdev->le_scan_window_discovery = DISCOV_LE_SCAN_WIN;
hdev->le_scan_int_adv_monitor = 0x0060;
hdev->le_scan_window_adv_monitor = 0x0030;
hdev->le_scan_int_connect = 0x0060;
hdev->le_scan_window_connect = 0x0060;
hdev->le_conn_min_interval = 0x0018;
......
......@@ -274,7 +274,7 @@ static ssize_t use_debug_keys_read(struct file *file, char __user *user_buf,
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS) ? 'Y': 'N';
buf[0] = hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS) ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
......@@ -292,7 +292,7 @@ static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf,
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = hci_dev_test_flag(hdev, HCI_SC_ONLY) ? 'Y': 'N';
buf[0] = hci_dev_test_flag(hdev, HCI_SC_ONLY) ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
......@@ -428,7 +428,7 @@ static ssize_t ssp_debug_mode_read(struct file *file, char __user *user_buf,
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = hdev->ssp_debug_mode ? 'Y': 'N';
buf[0] = hdev->ssp_debug_mode ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
......@@ -742,7 +742,7 @@ static ssize_t force_static_address_read(struct file *file,
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ? 'Y': 'N';
buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
......
......@@ -395,6 +395,29 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev);
}
static void hci_cc_set_event_filter(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *)skb->data);
struct hci_cp_set_event_filter *cp;
void *sent;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status)
return;
sent = hci_sent_cmd_data(hdev, HCI_OP_SET_EVENT_FLT);
if (!sent)
return;
cp = (struct hci_cp_set_event_filter *)sent;
if (cp->flt_type == HCI_FLT_CLEAR_ALL)
hci_dev_clear_flag(hdev, HCI_EVENT_FILTER_CONFIGURED);
else
hci_dev_set_flag(hdev, HCI_EVENT_FILTER_CONFIGURED);
}
static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
......@@ -1189,12 +1212,11 @@ static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev,
hci_dev_lock(hdev);
if (!hdev->cur_adv_instance) {
if (!cp->handle) {
/* Store in hdev for instance 0 (Set adv and Directed advs) */
bacpy(&hdev->random_addr, &cp->bdaddr);
} else {
adv_instance = hci_find_adv_instance(hdev,
hdev->cur_adv_instance);
adv_instance = hci_find_adv_instance(hdev, cp->handle);
if (adv_instance)
bacpy(&adv_instance->random_addr, &cp->bdaddr);
}
......@@ -1755,17 +1777,16 @@ static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_lock(hdev);
hdev->adv_addr_type = cp->own_addr_type;
if (!hdev->cur_adv_instance) {
if (!cp->handle) {
/* Store in hdev for instance 0 */
hdev->adv_tx_power = rp->tx_power;
} else {
adv_instance = hci_find_adv_instance(hdev,
hdev->cur_adv_instance);
adv_instance = hci_find_adv_instance(hdev, cp->handle);
if (adv_instance)
adv_instance->tx_power = rp->tx_power;
}
/* Update adv data as tx power is known now */
hci_req_update_adv_data(hdev, hdev->cur_adv_instance);
hci_req_update_adv_data(hdev, cp->handle);
hci_dev_unlock(hdev);
}
......@@ -3328,6 +3349,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cc_write_scan_enable(hdev, skb);
break;
case HCI_OP_SET_EVENT_FLT:
hci_cc_set_event_filter(hdev, skb);
break;
case HCI_OP_READ_CLASS_OF_DEV:
hci_cc_read_class_of_dev(hdev, skb);
break;
......@@ -5005,6 +5030,7 @@ static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
return;
hchan->handle = le16_to_cpu(ev->handle);
hchan->amp = true;
BT_DBG("hcon %p mgr %p hchan %p", hcon, hcon->amp_mgr, hchan);
......@@ -5037,7 +5063,7 @@ static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev,
hci_dev_lock(hdev);
hchan = hci_chan_lookup_handle(hdev, le16_to_cpu(ev->handle));
if (!hchan)
if (!hchan || !hchan->amp)
goto unlock;
amp_destroy_logical_link(hchan, ev->reason);
......@@ -5280,12 +5306,12 @@ static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (hdev->adv_addr_type != ADDR_LE_DEV_RANDOM)
return;
if (!hdev->cur_adv_instance) {
if (!ev->handle) {
bacpy(&conn->resp_addr, &hdev->random_addr);
return;
}
adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
adv_instance = hci_find_adv_instance(hdev, ev->handle);
if (adv_instance)
bacpy(&conn->resp_addr, &adv_instance->random_addr);
}
......@@ -5863,7 +5889,7 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev,
params->conn_latency = latency;
params->supervision_timeout = timeout;
store_hint = 0x01;
} else{
} else {
store_hint = 0x00;
}
......@@ -5911,7 +5937,7 @@ static void hci_le_phy_update_evt(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
if (!ev->status)
if (ev->status)
return;
hci_dev_lock(hdev);
......
......@@ -847,6 +847,10 @@ static u8 update_white_list(struct hci_request *req)
*/
bool allow_rpa = hdev->suspended;
if (use_ll_privacy(hdev) &&
hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
allow_rpa = true;
/* Go through the current white list programmed into the
* controller one by one and check if that address is still
* in the list of pending connections or list of devices to
......@@ -1131,14 +1135,14 @@ static void hci_req_clear_event_filter(struct hci_request *req)
{
struct hci_cp_set_event_filter f;
memset(&f, 0, sizeof(f));
f.flt_type = HCI_FLT_CLEAR_ALL;
hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &f);
if (!hci_dev_test_flag(req->hdev, HCI_BREDR_ENABLED))
return;
/* Update page scan state (since we may have modified it when setting
* the event filter).
*/
__hci_req_update_scan(req);
if (hci_dev_test_flag(req->hdev, HCI_EVENT_FILTER_CONFIGURED)) {
memset(&f, 0, sizeof(f));
f.flt_type = HCI_FLT_CLEAR_ALL;
hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &f);
}
}
static void hci_req_set_event_filter(struct hci_request *req)
......@@ -1147,6 +1151,10 @@ static void hci_req_set_event_filter(struct hci_request *req)
struct hci_cp_set_event_filter f;
struct hci_dev *hdev = req->hdev;
u8 scan = SCAN_DISABLED;
bool scanning = test_bit(HCI_PSCAN, &hdev->flags);
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
return;
/* Always clear event filter when starting */
hci_req_clear_event_filter(req);
......@@ -1167,12 +1175,13 @@ static void hci_req_set_event_filter(struct hci_request *req)
scan = SCAN_PAGE;
}
if (scan)
if (scan && !scanning) {
set_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks);
else
hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
} else if (!scan && scanning) {
set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}
}
static void cancel_adv_timeout(struct hci_dev *hdev)
......@@ -1315,9 +1324,14 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
hdev->advertising_paused = true;
hdev->advertising_old_state = old_state;
/* Disable page scan */
page_scan = SCAN_DISABLED;
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &page_scan);
/* Disable page scan if enabled */
if (test_bit(HCI_PSCAN, &hdev->flags)) {
page_scan = SCAN_DISABLED;
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1,
&page_scan);
set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
}
/* Disable LE passive scan if enabled */
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
......@@ -1328,9 +1342,6 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
/* Disable advertisement filters */
hci_req_add_set_adv_filter_enable(&req, false);
/* Mark task needing completion */
set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
/* Prevent disconnects from causing scanning to be re-enabled */
hdev->scanning_paused = true;
......@@ -1364,7 +1375,10 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
hdev->suspended = false;
hdev->scanning_paused = false;
/* Clear any event filters and restore scan state */
hci_req_clear_event_filter(&req);
__hci_req_update_scan(&req);
/* Reset passive/background scanning to normal */
__hci_update_background_scan(&req);
/* Enable all of the advertisement filters */
......@@ -1637,9 +1651,8 @@ static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
{
u8 scan_rsp_len = 0;
if (hdev->appearance) {
if (hdev->appearance)
scan_rsp_len = append_appearance(hdev, ptr, scan_rsp_len);
}
return append_local_name(hdev, ptr, scan_rsp_len);
}
......@@ -1657,9 +1670,8 @@ static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 instance,
instance_flags = adv_instance->flags;
if ((instance_flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance) {
if ((instance_flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance)
scan_rsp_len = append_appearance(hdev, ptr, scan_rsp_len);
}
memcpy(&ptr[scan_rsp_len], adv_instance->scan_rsp_data,
adv_instance->scan_rsp_len);
......@@ -2035,7 +2047,8 @@ int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
/* If Controller supports LL Privacy use own address type is
* 0x03
*/
if (use_ll_privacy(hdev))
if (use_ll_privacy(hdev) &&
hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
*own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
else
*own_addr_type = ADDR_LE_DEV_RANDOM;
......@@ -2170,7 +2183,8 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance)
cp.evt_properties = cpu_to_le16(LE_EXT_ADV_CONN_IND);
else
cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_IND);
} else if (adv_instance_is_scannable(hdev, instance)) {
} else if (adv_instance_is_scannable(hdev, instance) ||
(flags & MGMT_ADV_PARAM_SCAN_RSP)) {
if (secondary_adv)
cp.evt_properties = cpu_to_le16(LE_EXT_ADV_SCAN_IND);
else
......@@ -2508,7 +2522,8 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy,
/* If Controller supports LL Privacy use own address type is
* 0x03
*/
if (use_ll_privacy(hdev))
if (use_ll_privacy(hdev) &&
hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
*own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
else
*own_addr_type = ADDR_LE_DEV_RANDOM;
......@@ -2941,6 +2956,9 @@ static int bredr_inquiry(struct hci_request *req, unsigned long opt)
const u8 liac[3] = { 0x00, 0x8b, 0x9e };
struct hci_cp_inquiry cp;
if (test_bit(HCI_INQUIRY, &req->hdev->flags))
return 0;
bt_dev_dbg(req->hdev, "");
hci_dev_lock(req->hdev);
......@@ -3241,6 +3259,7 @@ bool hci_req_stop_discovery(struct hci_request *req)
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
cancel_delayed_work(&hdev->le_scan_disable);
cancel_delayed_work(&hdev->le_scan_restart);
hci_req_add_le_scan_disable(req, false);
}
......
......@@ -451,6 +451,8 @@ struct l2cap_chan *l2cap_chan_create(void)
if (!chan)
return NULL;
skb_queue_head_init(&chan->tx_q);
skb_queue_head_init(&chan->srej_q);
mutex_init(&chan->lock);
/* Set default lock nesting level */
......@@ -490,14 +492,14 @@ static void l2cap_chan_destroy(struct kref *kref)
void l2cap_chan_hold(struct l2cap_chan *c)
{
BT_DBG("chan %p orig refcnt %d", c, kref_read(&c->kref));
BT_DBG("chan %p orig refcnt %u", c, kref_read(&c->kref));
kref_get(&c->kref);
}
void l2cap_chan_put(struct l2cap_chan *c)
{
BT_DBG("chan %p orig refcnt %d", c, kref_read(&c->kref));
BT_DBG("chan %p orig refcnt %u", c, kref_read(&c->kref));
kref_put(&c->kref, l2cap_chan_destroy);
}
......@@ -516,7 +518,9 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan)
chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
chan->conf_state = 0;
set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
}
......@@ -648,7 +652,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
return;
switch(chan->mode) {
switch (chan->mode) {
case L2CAP_MODE_BASIC:
break;
......@@ -672,8 +676,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
skb_queue_purge(&chan->tx_q);
break;
}
return;
}
EXPORT_SYMBOL_GPL(l2cap_chan_del);
......@@ -1690,7 +1692,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
smp_conn_security(hcon, hcon->pending_sec_level);
/* For LE slave connections, make sure the connection interval
* is in the range of the minium and maximum interval that has
* is in the range of the minimum and maximum interval that has
* been configured for this connection. If not, then trigger
* the connection update procedure.
*/
......@@ -5921,7 +5923,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
struct l2cap_ecred_conn_req *req = (void *) data;
struct {
struct l2cap_ecred_conn_rsp rsp;
__le16 dcid[5];
__le16 dcid[L2CAP_ECRED_MAX_CID];
} __packed pdu;
struct l2cap_chan *chan, *pchan;
u16 mtu, mps;
......@@ -5938,6 +5940,14 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
goto response;
}
cmd_len -= sizeof(*req);
num_scid = cmd_len / sizeof(u16);
if (num_scid > ARRAY_SIZE(pdu.dcid)) {
result = L2CAP_CR_LE_INVALID_PARAMS;
goto response;
}
mtu = __le16_to_cpu(req->mtu);
mps = __le16_to_cpu(req->mps);
......@@ -5970,8 +5980,6 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
}
result = L2CAP_CR_LE_SUCCESS;
cmd_len -= sizeof(*req);
num_scid = cmd_len / sizeof(u16);
for (i = 0; i < num_scid; i++) {
u16 scid = __le16_to_cpu(req->scid[i]);
......@@ -7253,7 +7261,7 @@ static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
L2CAP_TXSEQ_EXPECTED) {
l2cap_pass_to_tx(chan, control);
BT_DBG("buffer_seq %d->%d", chan->buffer_seq,
BT_DBG("buffer_seq %u->%u", chan->buffer_seq,
__next_seq(chan, chan->buffer_seq));
chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
......@@ -7542,7 +7550,7 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
BT_DBG("chan %p, len %d", chan, skb->len);
/* If we receive data on a fixed channel before the info req/rsp
* procdure is done simply assume that the channel is supported
* procedure is done simply assume that the channel is supported
* and mark it as ready.
*/
if (chan->chan_type == L2CAP_CHAN_FIXED)
......@@ -7762,7 +7770,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
return conn;
}
static bool is_valid_psm(u16 psm, u8 dst_type) {
static bool is_valid_psm(u16 psm, u8 dst_type)
{
if (!psm)
return false;
......@@ -8356,7 +8365,7 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
if (!conn)
goto drop;
BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
BT_DBG("conn %p len %u flags 0x%x", conn, skb->len, flags);
switch (flags) {
case ACL_START:
......@@ -8386,10 +8395,10 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
return;
}
BT_DBG("Start: total len %d, frag len %d", len, skb->len);
BT_DBG("Start: total len %d, frag len %u", len, skb->len);
if (skb->len > len) {
BT_ERR("Frame is too long (len %d, expected len %d)",
BT_ERR("Frame is too long (len %u, expected len %d)",
skb->len, len);
l2cap_conn_unreliable(conn, ECOMM);
goto drop;
......@@ -8402,7 +8411,7 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
break;
case ACL_CONT:
BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
BT_DBG("Cont: frag len %u (expecting %u)", skb->len, conn->rx_len);
if (!conn->rx_skb) {
BT_ERR("Unexpected continuation frame (len %d)", skb->len);
......@@ -8423,7 +8432,7 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
}
if (skb->len > conn->rx_len) {
BT_ERR("Fragment is too long (len %d, expected %d)",
BT_ERR("Fragment is too long (len %u, expected %u)",
skb->len, conn->rx_len);
l2cap_recv_reset(conn);
l2cap_conn_unreliable(conn, ECOMM);
......
......@@ -179,9 +179,17 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct sockaddr_l2 la;
int len, err = 0;
bool zapped;
BT_DBG("sk %p", sk);
lock_sock(sk);
zapped = sock_flag(sk, SOCK_ZAPPED);
release_sock(sk);
if (zapped)
return -EINVAL;
if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
......
......@@ -40,7 +40,7 @@
#include "msft.h"
#define MGMT_VERSION 1
#define MGMT_REVISION 19
#define MGMT_REVISION 20
static const u16 mgmt_commands[] = {
MGMT_OP_READ_INDEX_LIST,
......@@ -108,6 +108,8 @@ static const u16 mgmt_commands[] = {
MGMT_OP_START_LIMITED_DISCOVERY,
MGMT_OP_READ_EXT_INFO,
MGMT_OP_SET_APPEARANCE,
MGMT_OP_GET_PHY_CONFIGURATION,
MGMT_OP_SET_PHY_CONFIGURATION,
MGMT_OP_SET_BLOCKED_KEYS,
MGMT_OP_SET_WIDEBAND_SPEECH,
MGMT_OP_READ_CONTROLLER_CAP,
......@@ -166,6 +168,8 @@ static const u16 mgmt_events[] = {
MGMT_EV_PHY_CONFIGURATION_CHANGED,
MGMT_EV_EXP_FEATURE_CHANGED,
MGMT_EV_DEVICE_FLAGS_CHANGED,
MGMT_EV_ADV_MONITOR_ADDED,
MGMT_EV_ADV_MONITOR_REMOVED,
MGMT_EV_CONTROLLER_SUSPEND,
MGMT_EV_CONTROLLER_RESUME,
};
......@@ -196,8 +200,6 @@ static const u16 mgmt_untrusted_events[] = {
MGMT_EV_EXT_INDEX_REMOVED,
MGMT_EV_EXT_INFO_CHANGED,
MGMT_EV_EXP_FEATURE_CHANGED,
MGMT_EV_ADV_MONITOR_ADDED,
MGMT_EV_ADV_MONITOR_REMOVED,
};
#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
......@@ -3728,8 +3730,11 @@ static int read_controller_cap(struct sock *sk, struct hci_dev *hdev,
/* When the Read Simple Pairing Options command is supported, then
* the remote public key validation is supported.
*
* Alternatively, when Microsoft extensions are available, they can
* indicate support for public key validation as well.
*/
if (hdev->commands[41] & 0x08)
if ((hdev->commands[41] & 0x08) || msft_curve_validity(hdev))
flags |= 0x01; /* Remote public key validation (BR/EDR) */
flags |= 0x02; /* Remote public key validation (LE) */
......@@ -3982,7 +3987,7 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
if (hdev_is_powered(hdev))
return mgmt_cmd_status(sk, hdev->id,
MGMT_OP_SET_EXP_FEATURE,
MGMT_STATUS_NOT_POWERED);
MGMT_STATUS_REJECTED);
/* Parameters are limited to a single octet */
if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
......@@ -7432,6 +7437,7 @@ static u32 get_supported_adv_flags(struct hci_dev *hdev)
flags |= MGMT_ADV_PARAM_TIMEOUT;
flags |= MGMT_ADV_PARAM_INTERVALS;
flags |= MGMT_ADV_PARAM_TX_POWER;
flags |= MGMT_ADV_PARAM_SCAN_RSP;
/* In extended adv TX_POWER returned from Set Adv Param
* will be always valid.
......@@ -7475,7 +7481,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
* advertising.
*/
if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
MGMT_STATUS_NOT_SUPPORTED);
hci_dev_lock(hdev);
......@@ -7976,7 +7982,6 @@ static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}
hdev->cur_adv_instance = cp->instance;
/* Submit request for advertising params if ext adv available */
if (ext_adv_capable(hdev)) {
hci_req_init(&req, hdev);
......
......@@ -142,6 +142,9 @@ static bool read_supported_features(struct hci_dev *hdev,
msft->evt_prefix_len = rp->evt_prefix_len;
msft->features = __le64_to_cpu(rp->features);
if (msft->features & MSFT_FEATURE_MASK_CURVE_VALIDITY)
hdev->msft_curve_validity = true;
kfree_skb(skb);
return true;
......@@ -605,3 +608,8 @@ int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
return err;
}
bool msft_curve_validity(struct hci_dev *hdev)
{
return hdev->msft_curve_validity;
}
......@@ -22,6 +22,7 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle);
void msft_req_add_set_filter_enable(struct hci_request *req, bool enable);
int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
bool msft_curve_validity(struct hci_dev *hdev);
#else
......@@ -54,4 +55,9 @@ static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
return -EOPNOTSUPP;
}
static inline bool msft_curve_validity(struct hci_dev *hdev)
{
return false;
}
#endif
......@@ -51,8 +51,8 @@ struct sco_conn {
unsigned int mtu;
};
#define sco_conn_lock(c) spin_lock(&c->lock);
#define sco_conn_unlock(c) spin_unlock(&c->lock);
#define sco_conn_lock(c) spin_lock(&c->lock)
#define sco_conn_unlock(c) spin_unlock(&c->lock)
static void sco_sock_close(struct sock *sk);
static void sco_sock_kill(struct sock *sk);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment