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: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmBvL7UZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKU+eD/4qGiwnwQVia4hjnQ5PZ0c/ sBmZvzzZE43RNRvy8gAwcVLypLaiIkEYml4ruVdF6RGoqaDA6kRB7D0tdk8EtZc4 6h72LX0zefnyZNj/Fcl6+dKuq7bSHjdOK0G+oXFmpvYfScPsI6Oq0ntpYOFYwUE0 cDdeZyb/sW4f6L5AXUgLjD9AIjzlBOJEU5HcRL/uY+E/fH1oe757/IhUDerXjTIh 9EhY28mrI7KeoEcJ1NIgvjPnRCxPRLAKgrzc8NXkUsLeNZSIywrwjgRfTvCZ+qQf g/MmNv+n7yFlUzA7Fu2d8YAgRtgF9nZc45geqOSHqcSZURORSs0CzEoYinqwT7f0 xdMBi/UoSzJsLksgv+OfXOyoQ4lPNJ47pcH/edmT/ZJ/Ai2yTqUUSODHQ3MLC4Dp kQj34thQvfTf5b6+9HwKmBjlfMK0QGPqWjp6dth2bzos/ugurDP+XimAv0urvFz+ NkES5kCMUs/1z7Yh+Nj1MyU3Wfdwol0wOh+PXBTAw2fxSy6kmKYGyLw7HEdWegB0 K2w/ZS58g0EGK89ZSiqlZKmXtAd22dQqS6JlZje+9YTtEtRWu+rAF1dddS8vJDjl Rq3VSQ1B6Qw0rdGpyfxdgm/sWwq5S1YgQQcAZgVaeo9ZiIhfscVD5v5L0Ol6k9ms 3eCK/2brsX0IaV61eVnoOw== =jiCz -----END PGP SIGNATURE----- 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: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
4438669eb7
@ -1,56 +0,0 @@
|
||||
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];
|
||||
};
|
||||
};
|
118
Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml
Normal file
118
Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml
Normal file
@ -0,0 +1,118 @@
|
||||
# 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
|
||||
|
@ -24,6 +24,14 @@
|
||||
#define ECDSA_OFFSET 644
|
||||
#define ECDSA_HEADER_LEN 320
|
||||
|
||||
#define CMD_WRITE_BOOT_PARAMS 0xfc0e
|
||||
struct cmd_write_boot_params {
|
||||
u32 boot_addr;
|
||||
u8 fw_build_num;
|
||||
u8 fw_build_ww;
|
||||
u8 fw_build_yy;
|
||||
} __packed;
|
||||
|
||||
int btintel_check_bdaddr(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_rp_read_bd_addr *bda;
|
||||
@ -208,10 +216,39 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_hw_error);
|
||||
|
||||
void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
|
||||
int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
|
||||
{
|
||||
const char *variant;
|
||||
|
||||
/* The hardware platform number has a fixed value of 0x37 and
|
||||
* for now only accept this single value.
|
||||
*/
|
||||
if (ver->hw_platform != 0x37) {
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
|
||||
ver->hw_platform);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check for supported iBT hardware variants of this firmware
|
||||
* loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
switch (ver->hw_variant) {
|
||||
case 0x0b: /* SfP */
|
||||
case 0x0c: /* WsP */
|
||||
case 0x11: /* JfP */
|
||||
case 0x12: /* ThP */
|
||||
case 0x13: /* HrP */
|
||||
case 0x14: /* CcP */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
|
||||
ver->hw_variant);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (ver->fw_variant) {
|
||||
case 0x06:
|
||||
variant = "Bootloader";
|
||||
@ -220,13 +257,16 @@ void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
|
||||
variant = "Firmware";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
bt_dev_err(hdev, "Unsupported firmware variant(%02x)", ver->fw_variant);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bt_dev_info(hdev, "%s revision %u.%u build %u week %u %u",
|
||||
variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
|
||||
ver->fw_build_num, ver->fw_build_ww,
|
||||
2000 + ver->fw_build_yy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_version_info);
|
||||
|
||||
@ -364,13 +404,56 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_read_version);
|
||||
|
||||
void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
|
||||
int btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
|
||||
{
|
||||
const char *variant;
|
||||
|
||||
/* The hardware platform number has a fixed value of 0x37 and
|
||||
* for now only accept this single value.
|
||||
*/
|
||||
if (INTEL_HW_PLATFORM(version->cnvi_bt) != 0x37) {
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)",
|
||||
INTEL_HW_PLATFORM(version->cnvi_bt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check for supported iBT hardware variants of this firmware
|
||||
* loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
switch (INTEL_HW_VARIANT(version->cnvi_bt)) {
|
||||
case 0x17: /* TyP */
|
||||
case 0x18: /* Slr */
|
||||
case 0x19: /* Slr-F */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
|
||||
INTEL_HW_VARIANT(version->cnvi_bt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (version->img_type) {
|
||||
case 0x01:
|
||||
variant = "Bootloader";
|
||||
/* It is required that every single firmware fragment is acknowledged
|
||||
* with a command complete event. If the boot parameters indicate
|
||||
* that this bootloader does not send them, then abort the setup.
|
||||
*/
|
||||
if (version->limited_cce != 0x00) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware loading method (0x%x)",
|
||||
version->limited_cce);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */
|
||||
if (version->sbe_type > 0x01) {
|
||||
bt_dev_err(hdev, "Unsupported Intel secure boot engine type (0x%x)",
|
||||
version->sbe_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bt_dev_info(hdev, "Device revision is %u", version->dev_rev_id);
|
||||
bt_dev_info(hdev, "Secure boot is %s",
|
||||
version->secure_boot ? "enabled" : "disabled");
|
||||
@ -389,15 +472,14 @@ void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *ve
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported image type(%02x)", version->img_type);
|
||||
goto done;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,
|
||||
2000 + (version->timestamp >> 8), version->timestamp & 0xff,
|
||||
version->build_type, version->build_num);
|
||||
|
||||
done:
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_version_info_tlv);
|
||||
|
||||
@ -455,12 +537,23 @@ int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver
|
||||
version->img_type = tlv->val[0];
|
||||
break;
|
||||
case INTEL_TLV_TIME_STAMP:
|
||||
/* If image type is Operational firmware (0x03), then
|
||||
* running FW Calendar Week and Year information can
|
||||
* be extracted from Timestamp information
|
||||
*/
|
||||
version->min_fw_build_cw = tlv->val[0];
|
||||
version->min_fw_build_yy = tlv->val[1];
|
||||
version->timestamp = get_unaligned_le16(tlv->val);
|
||||
break;
|
||||
case INTEL_TLV_BUILD_TYPE:
|
||||
version->build_type = tlv->val[0];
|
||||
break;
|
||||
case INTEL_TLV_BUILD_NUM:
|
||||
/* If image type is Operational firmware (0x03), then
|
||||
* running FW build number can be extracted from the
|
||||
* Build information
|
||||
*/
|
||||
version->min_fw_build_nn = tlv->val[0];
|
||||
version->build_num = get_unaligned_le32(tlv->val);
|
||||
break;
|
||||
case INTEL_TLV_SECURE_BOOT:
|
||||
@ -841,7 +934,7 @@ static int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev,
|
||||
|
||||
static int btintel_download_firmware_payload(struct hci_dev *hdev,
|
||||
const struct firmware *fw,
|
||||
u32 *boot_param, size_t offset)
|
||||
size_t offset)
|
||||
{
|
||||
int err;
|
||||
const u8 *fw_ptr;
|
||||
@ -854,20 +947,6 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev,
|
||||
while (fw_ptr - fw->data < fw->size) {
|
||||
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
|
||||
|
||||
/* Each SKU has a different reset parameter to use in the
|
||||
* HCI_Intel_Reset command and it is embedded in the firmware
|
||||
* data. So, instead of using static value per SKU, check
|
||||
* the firmware data and save it for later use.
|
||||
*/
|
||||
if (le16_to_cpu(cmd->opcode) == 0xfc0e) {
|
||||
/* The boot parameter is the first 32-bit value
|
||||
* and rest of 3 octets are reserved.
|
||||
*/
|
||||
*boot_param = get_unaligned_le32(fw_ptr + sizeof(*cmd));
|
||||
|
||||
bt_dev_dbg(hdev, "boot_param=0x%x", *boot_param);
|
||||
}
|
||||
|
||||
frag_len += sizeof(*cmd) + cmd->plen;
|
||||
|
||||
/* The parameter length of the secure send command requires
|
||||
@ -896,28 +975,131 @@ done:
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool btintel_firmware_version(struct hci_dev *hdev,
|
||||
u8 num, u8 ww, u8 yy,
|
||||
const struct firmware *fw,
|
||||
u32 *boot_addr)
|
||||
{
|
||||
const u8 *fw_ptr;
|
||||
|
||||
fw_ptr = fw->data;
|
||||
|
||||
while (fw_ptr - fw->data < fw->size) {
|
||||
struct hci_command_hdr *cmd = (void *)(fw_ptr);
|
||||
|
||||
/* Each SKU has a different reset parameter to use in the
|
||||
* HCI_Intel_Reset command and it is embedded in the firmware
|
||||
* data. So, instead of using static value per SKU, check
|
||||
* the firmware data and save it for later use.
|
||||
*/
|
||||
if (le16_to_cpu(cmd->opcode) == CMD_WRITE_BOOT_PARAMS) {
|
||||
struct cmd_write_boot_params *params;
|
||||
|
||||
params = (void *)(fw_ptr + sizeof(*cmd));
|
||||
|
||||
bt_dev_info(hdev, "Boot Address: 0x%x",
|
||||
le32_to_cpu(params->boot_addr));
|
||||
|
||||
bt_dev_info(hdev, "Firmware Version: %u-%u.%u",
|
||||
params->fw_build_num, params->fw_build_ww,
|
||||
params->fw_build_yy);
|
||||
|
||||
return (num == params->fw_build_num &&
|
||||
ww == params->fw_build_ww &&
|
||||
yy == params->fw_build_yy);
|
||||
}
|
||||
|
||||
fw_ptr += sizeof(*cmd) + cmd->plen;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int btintel_download_firmware(struct hci_dev *hdev,
|
||||
struct intel_version *ver,
|
||||
const struct firmware *fw,
|
||||
u32 *boot_param)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* SfP and WsP don't seem to update the firmware version on file
|
||||
* so version checking is currently not possible.
|
||||
*/
|
||||
switch (ver->hw_variant) {
|
||||
case 0x0b: /* SfP */
|
||||
case 0x0c: /* WsP */
|
||||
/* Skip version checking */
|
||||
break;
|
||||
default:
|
||||
/* Skip reading firmware file version in bootloader mode */
|
||||
if (ver->fw_variant == 0x06)
|
||||
break;
|
||||
|
||||
/* Skip download if firmware has the same version */
|
||||
if (btintel_firmware_version(hdev, ver->fw_build_num,
|
||||
ver->fw_build_ww, ver->fw_build_yy,
|
||||
fw, boot_param)) {
|
||||
bt_dev_info(hdev, "Firmware already loaded");
|
||||
/* Return -EALREADY to indicate that the firmware has
|
||||
* already been loaded.
|
||||
*/
|
||||
return -EALREADY;
|
||||
}
|
||||
}
|
||||
|
||||
/* The firmware variant determines if the device is in bootloader
|
||||
* mode or is running operational firmware. The value 0x06 identifies
|
||||
* the bootloader and the value 0x23 identifies the operational
|
||||
* firmware.
|
||||
*
|
||||
* If the firmware version has changed that means it needs to be reset
|
||||
* to bootloader when operational so the new firmware can be loaded.
|
||||
*/
|
||||
if (ver->fw_variant == 0x23)
|
||||
return -EINVAL;
|
||||
|
||||
err = btintel_sfi_rsa_header_secure_send(hdev, fw);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return btintel_download_firmware_payload(hdev, fw, boot_param,
|
||||
RSA_HEADER_LEN);
|
||||
return btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btintel_download_firmware);
|
||||
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
u32 css_header_ver;
|
||||
|
||||
/* Skip reading firmware file version in bootloader mode */
|
||||
if (ver->img_type != 0x01) {
|
||||
/* Skip download if firmware has the same version */
|
||||
if (btintel_firmware_version(hdev, ver->min_fw_build_nn,
|
||||
ver->min_fw_build_cw,
|
||||
ver->min_fw_build_yy,
|
||||
fw, boot_param)) {
|
||||
bt_dev_info(hdev, "Firmware already loaded");
|
||||
/* Return -EALREADY to indicate that firmware has
|
||||
* already been loaded.
|
||||
*/
|
||||
return -EALREADY;
|
||||
}
|
||||
}
|
||||
|
||||
/* The firmware variant determines if the device is in bootloader
|
||||
* mode or is running operational firmware. The value 0x01 identifies
|
||||
* the bootloader and the value 0x03 identifies the operational
|
||||
* firmware.
|
||||
*
|
||||
* If the firmware version has changed that means it needs to be reset
|
||||
* to bootloader when operational so the new firmware can be loaded.
|
||||
*/
|
||||
if (ver->img_type == 0x03)
|
||||
return -EINVAL;
|
||||
|
||||
/* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support
|
||||
* only RSA secure boot engine. Hence, the corresponding sfi file will
|
||||
* have RSA header of 644 bytes followed by Command Buffer.
|
||||
@ -947,7 +1129,7 @@ int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = btintel_download_firmware_payload(hdev, fw, boot_param, RSA_HEADER_LEN);
|
||||
err = btintel_download_firmware_payload(hdev, fw, RSA_HEADER_LEN);
|
||||
if (err)
|
||||
return err;
|
||||
} else if (hw_variant >= 0x17) {
|
||||
@ -968,7 +1150,6 @@ int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
return err;
|
||||
|
||||
err = btintel_download_firmware_payload(hdev, fw,
|
||||
boot_param,
|
||||
RSA_HEADER_LEN + ECDSA_HEADER_LEN);
|
||||
if (err)
|
||||
return err;
|
||||
@ -978,7 +1159,6 @@ int btintel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
return err;
|
||||
|
||||
err = btintel_download_firmware_payload(hdev, fw,
|
||||
boot_param,
|
||||
RSA_HEADER_LEN + ECDSA_HEADER_LEN);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -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,
|
||||
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,
|
||||
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,
|
||||
|
@ -399,7 +399,9 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
|
||||
/* MediaTek Bluetooth devices */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x0e8d, 0xe0, 0x01, 0x01),
|
||||
.driver_info = BTUSB_MEDIATEK },
|
||||
.driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
|
||||
/* Additional MediaTek MT7615E Bluetooth devices */
|
||||
{ USB_DEVICE(0x13d3, 0x3560), .driver_info = BTUSB_MEDIATEK},
|
||||
@ -455,6 +457,8 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0xc123), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0cb5, 0xc547), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Silicon Wave based devices */
|
||||
{ USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },
|
||||
@ -2400,7 +2404,7 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
|
||||
static int btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
|
||||
struct intel_boot_params *params,
|
||||
char *fw_name, size_t len,
|
||||
const char *suffix)
|
||||
@ -2424,9 +2428,10 @@ static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
|
||||
suffix);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btusb_setup_intel_newgen_get_fw_name(const struct intel_version_tlv *ver_tlv,
|
||||
@ -2444,6 +2449,44 @@ static void btusb_setup_intel_newgen_get_fw_name(const struct intel_version_tlv
|
||||
suffix);
|
||||
}
|
||||
|
||||
static int btusb_download_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
ktime_t delta, rettime;
|
||||
unsigned long long duration;
|
||||
int err;
|
||||
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
|
||||
bt_dev_info(hdev, "Waiting for firmware download to complete");
|
||||
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(msec));
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Firmware loading interrupted");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Firmware loading timeout");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) {
|
||||
bt_dev_err(hdev, "Firmware loading failed");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
||||
|
||||
bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
struct intel_version_tlv *ver,
|
||||
u32 *boot_param)
|
||||
@ -2452,19 +2495,11 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
char fwname[64];
|
||||
int err;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
ktime_t calltime;
|
||||
|
||||
if (!ver || !boot_param)
|
||||
return -EINVAL;
|
||||
|
||||
/* The hardware platform number has a fixed value of 0x37 and
|
||||
* for now only accept this single value.
|
||||
*/
|
||||
if (INTEL_HW_PLATFORM(ver->cnvi_bt) != 0x37) {
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)",
|
||||
INTEL_HW_PLATFORM(ver->cnvi_bt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The firmware variant determines if the device is in bootloader
|
||||
* mode or is running operational firmware. The value 0x03 identifies
|
||||
* the bootloader and the value 0x23 identifies the operational
|
||||
@ -2481,50 +2516,6 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
if (ver->img_type == 0x03) {
|
||||
clear_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
btintel_check_bdaddr(hdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for supported iBT hardware variants of this firmware
|
||||
* loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
switch (INTEL_HW_VARIANT(ver->cnvi_bt)) {
|
||||
case 0x17: /* TyP */
|
||||
case 0x18: /* Slr */
|
||||
case 0x19: /* Slr-F */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
|
||||
INTEL_HW_VARIANT(ver->cnvi_bt));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If the device is not in bootloader mode, then the only possible
|
||||
* choice is to return an error and abort the device initialization.
|
||||
*/
|
||||
if (ver->img_type != 0x01) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware variant (0x%x)",
|
||||
ver->img_type);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* It is required that every single firmware fragment is acknowledged
|
||||
* with a command complete event. If the boot parameters indicate
|
||||
* that this bootloader does not send them, then abort the setup.
|
||||
*/
|
||||
if (ver->limited_cce != 0x00) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware loading method (0x%x)",
|
||||
ver->limited_cce);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */
|
||||
if (ver->sbe_type > 0x01) {
|
||||
bt_dev_err(hdev, "Unsupported Intel secure boot engine type (0x%x)",
|
||||
ver->sbe_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If the OTP has no valid Bluetooth device address, then there will
|
||||
@ -2538,7 +2529,8 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
btusb_setup_intel_newgen_get_fw_name(ver, fwname, sizeof(fwname), "sfi");
|
||||
err = request_firmware(&fw, fwname, &hdev->dev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to load Intel firmware file (%d)", err);
|
||||
bt_dev_err(hdev, "Failed to load Intel firmware file %s (%d)",
|
||||
fwname, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2551,22 +2543,28 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
goto done;
|
||||
}
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
set_bit(BTUSB_DOWNLOADING, &data->flags);
|
||||
|
||||
/* Start firmware downloading and get boot parameter */
|
||||
err = btintel_download_firmware_newgen(hdev, fw, boot_param,
|
||||
err = btintel_download_firmware_newgen(hdev, ver, fw, boot_param,
|
||||
INTEL_HW_VARIANT(ver->cnvi_bt),
|
||||
ver->sbe_type);
|
||||
if (err < 0) {
|
||||
if (err == -EALREADY) {
|
||||
/* Firmware has already been loaded */
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
err = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* When FW download fails, send Intel Reset to retry
|
||||
* FW download.
|
||||
*/
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
|
||||
bt_dev_info(hdev, "Waiting for firmware download to complete");
|
||||
|
||||
/* Before switching the device into operational mode and with that
|
||||
* booting the loaded firmware, wait for the bootloader notification
|
||||
@ -2579,26 +2577,9 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev,
|
||||
* and thus just timeout if that happens and fail the setup
|
||||
* of this device.
|
||||
*/
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(5000));
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Firmware loading interrupted");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Firmware loading timeout");
|
||||
err = -ETIMEDOUT;
|
||||
err = btusb_download_wait(hdev, calltime, 5000);
|
||||
if (err == -ETIMEDOUT)
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) {
|
||||
bt_dev_err(hdev, "Firmware loading failed");
|
||||
err = -ENOEXEC;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
release_firmware(fw);
|
||||
@ -2614,41 +2595,11 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
char fwname[64];
|
||||
int err;
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
ktime_t calltime;
|
||||
|
||||
if (!ver || !params)
|
||||
return -EINVAL;
|
||||
|
||||
/* The hardware platform number has a fixed value of 0x37 and
|
||||
* for now only accept this single value.
|
||||
*/
|
||||
if (ver->hw_platform != 0x37) {
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
|
||||
ver->hw_platform);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check for supported iBT hardware variants of this firmware
|
||||
* loading method.
|
||||
*
|
||||
* This check has been put in place to ensure correct forward
|
||||
* compatibility options when newer hardware variants come along.
|
||||
*/
|
||||
switch (ver->hw_variant) {
|
||||
case 0x0b: /* SfP */
|
||||
case 0x0c: /* WsP */
|
||||
case 0x11: /* JfP */
|
||||
case 0x12: /* ThP */
|
||||
case 0x13: /* HrP */
|
||||
case 0x14: /* CcP */
|
||||
break;
|
||||
default:
|
||||
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
|
||||
ver->hw_variant);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
btintel_version_info(hdev, ver);
|
||||
|
||||
/* The firmware variant determines if the device is in bootloader
|
||||
* mode or is running operational firmware. The value 0x06 identifies
|
||||
* the bootloader and the value 0x23 identifies the operational
|
||||
@ -2665,16 +2616,18 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
if (ver->fw_variant == 0x23) {
|
||||
clear_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
btintel_check_bdaddr(hdev);
|
||||
|
||||
/* SfP and WsP don't seem to update the firmware version on file
|
||||
* so version checking is currently possible.
|
||||
*/
|
||||
switch (ver->hw_variant) {
|
||||
case 0x0b: /* SfP */
|
||||
case 0x0c: /* WsP */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the device is not in bootloader mode, then the only possible
|
||||
* choice is to return an error and abort the device initialization.
|
||||
*/
|
||||
if (ver->fw_variant != 0x06) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware variant (%u)",
|
||||
ver->fw_variant);
|
||||
return -ENODEV;
|
||||
/* Proceed to download to check if the version matches */
|
||||
goto download;
|
||||
}
|
||||
|
||||
/* Read the secure boot parameters to identify the operating
|
||||
@ -2702,6 +2655,7 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
|
||||
}
|
||||
|
||||
download:
|
||||
/* With this Intel bootloader only the hardware variant and device
|
||||
* revision information are used to select the right firmware for SfP
|
||||
* and WsP.
|
||||
@ -2725,14 +2679,15 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
*/
|
||||
err = btusb_setup_intel_new_get_fw_name(ver, params, fwname,
|
||||
sizeof(fwname), "sfi");
|
||||
if (!err) {
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware naming");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = request_firmware(&fw, fwname, &hdev->dev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to load Intel firmware file (%d)", err);
|
||||
bt_dev_err(hdev, "Failed to load Intel firmware file %s (%d)",
|
||||
fwname, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2745,20 +2700,26 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
goto done;
|
||||
}
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
set_bit(BTUSB_DOWNLOADING, &data->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) {
|
||||
if (err == -EALREADY) {
|
||||
/* Firmware has already been loaded */
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
err = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* When FW download fails, send Intel Reset to retry
|
||||
* FW download.
|
||||
*/
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
|
||||
|
||||
bt_dev_info(hdev, "Waiting for firmware download to complete");
|
||||
|
||||
/* Before switching the device into operational mode and with that
|
||||
* booting the loaded firmware, wait for the bootloader notification
|
||||
@ -2771,84 +2732,57 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
|
||||
* and thus just timeout if that happens and fail the setup
|
||||
* of this device.
|
||||
*/
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(5000));
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Firmware loading interrupted");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Firmware loading timeout");
|
||||
err = -ETIMEDOUT;
|
||||
err = btusb_download_wait(hdev, calltime, 5000);
|
||||
if (err == -ETIMEDOUT)
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) {
|
||||
bt_dev_err(hdev, "Firmware loading failed");
|
||||
err = -ENOEXEC;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
release_firmware(fw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btusb_setup_intel_new(struct hci_dev *hdev)
|
||||
static int btusb_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct intel_version ver;
|
||||
struct intel_boot_params params;
|
||||
u32 boot_param;
|
||||
char ddcname[64];
|
||||
ktime_t calltime, delta, rettime;
|
||||
ktime_t delta, rettime;
|
||||
unsigned long long duration;
|
||||
int err;
|
||||
struct intel_debug_features features;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
bt_dev_info(hdev, "Waiting for device to boot");
|
||||
|
||||
/* Set the default boot parameter to 0x0 and it is updated to
|
||||
* SKU specific boot parameter after reading Intel_Write_Boot_Params
|
||||
* command while downloading the firmware.
|
||||
*/
|
||||
boot_param = 0x00000000;
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
/* Read the Intel version information to determine if the device
|
||||
* is in bootloader mode or if it already has operational firmware
|
||||
* loaded.
|
||||
*/
|
||||
err = btintel_read_version(hdev, &ver);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Read version failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return err;
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_BOOTING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(msec));
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Device boot interrupted");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
err = btusb_intel_download_firmware(hdev, &ver, ¶ms, &boot_param);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* controller is already having an operational firmware */
|
||||
if (ver.fw_variant == 0x23)
|
||||
goto finish;
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Device boot timeout");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
|
||||
|
||||
bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
|
||||
bt_dev_info(hdev, "Device booted in %llu usecs", duration);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_intel_boot(struct hci_dev *hdev, u32 boot_addr)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
ktime_t calltime;
|
||||
int err;
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
set_bit(BTUSB_BOOTING, &data->flags);
|
||||
|
||||
err = btintel_send_intel_reset(hdev, boot_param);
|
||||
err = btintel_send_intel_reset(hdev, boot_addr);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
@ -2862,35 +2796,64 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
|
||||
* 1 second. However if that happens, then just fail the setup
|
||||
* since something went wrong.
|
||||
*/
|
||||
bt_dev_info(hdev, "Waiting for device to boot");
|
||||
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_BOOTING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(1000));
|
||||
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Device boot interrupted");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Device boot timeout");
|
||||
err = btusb_boot_wait(hdev, calltime, 1000);
|
||||
if (err == -ETIMEDOUT)
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btusb_setup_intel_new(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct intel_version ver;
|
||||
struct intel_boot_params params;
|
||||
u32 boot_param;
|
||||
char ddcname[64];
|
||||
int err;
|
||||
struct intel_debug_features features;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
/* Set the default boot parameter to 0x0 and it is updated to
|
||||
* SKU specific boot parameter after reading Intel_Write_Boot_Params
|
||||
* command while downloading the firmware.
|
||||
*/
|
||||
boot_param = 0x00000000;
|
||||
|
||||
/* Read the Intel version information to determine if the device
|
||||
* is in bootloader mode or if it already has operational firmware
|
||||
* loaded.
|
||||
*/
|
||||
err = btintel_read_version(hdev, &ver);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Read version failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
|
||||
err = btintel_version_info(hdev, &ver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bt_dev_info(hdev, "Device booted in %llu usecs", duration);
|
||||
err = btusb_intel_download_firmware(hdev, &ver, ¶ms, &boot_param);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* controller is already having an operational firmware */
|
||||
if (ver.fw_variant == 0x23)
|
||||
goto finish;
|
||||
|
||||
err = btusb_intel_boot(hdev, boot_param);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
clear_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
|
||||
err = btusb_setup_intel_new_get_fw_name(&ver, ¶ms, ddcname,
|
||||
sizeof(ddcname), "ddc");
|
||||
|
||||
if (!err) {
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Unsupported Intel firmware naming");
|
||||
} else {
|
||||
/* Once the device is running in operational mode, it needs to
|
||||
@ -2947,8 +2910,6 @@ static int btusb_setup_intel_newgen(struct hci_dev *hdev)
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
u32 boot_param;
|
||||
char ddcname[64];
|
||||
ktime_t calltime, delta, rettime;
|
||||
unsigned long long duration;
|
||||
int err;
|
||||
struct intel_debug_features features;
|
||||
struct intel_version_tlv version;
|
||||
@ -2961,8 +2922,6 @@ static int btusb_setup_intel_newgen(struct hci_dev *hdev)
|
||||
*/
|
||||
boot_param = 0x00000000;
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
/* Read the Intel version information to determine if the device
|
||||
* is in bootloader mode or if it already has operational firmware
|
||||
* loaded.
|
||||
@ -2974,7 +2933,9 @@ static int btusb_setup_intel_newgen(struct hci_dev *hdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
btintel_version_info_tlv(hdev, &version);
|
||||
err = btintel_version_info_tlv(hdev, &version);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = btusb_intel_download_firmware_newgen(hdev, &version, &boot_param);
|
||||
if (err)
|
||||
@ -2984,52 +2945,9 @@ static int btusb_setup_intel_newgen(struct hci_dev *hdev)
|
||||
if (version.img_type == 0x03)
|
||||
goto finish;
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
||||
|
||||
bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
|
||||
|
||||
calltime = ktime_get();
|
||||
|
||||
set_bit(BTUSB_BOOTING, &data->flags);
|
||||
|
||||
err = btintel_send_intel_reset(hdev, boot_param);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err);
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
err = btusb_intel_boot(hdev, boot_param);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The bootloader will not indicate when the device is ready. This
|
||||
* is done by the operational firmware sending bootup notification.
|
||||
*
|
||||
* Booting into operational firmware should not take longer than
|
||||
* 1 second. However if that happens, then just fail the setup
|
||||
* since something went wrong.
|
||||
*/
|
||||
bt_dev_info(hdev, "Waiting for device to boot");
|
||||
|
||||
err = wait_on_bit_timeout(&data->flags, BTUSB_BOOTING,
|
||||
TASK_INTERRUPTIBLE,
|
||||
msecs_to_jiffies(1000));
|
||||
|
||||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Device boot interrupted");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Device boot timeout");
|
||||
btintel_reset_to_bootloader(hdev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
rettime = ktime_get();
|
||||
delta = ktime_sub(rettime, calltime);
|
||||
duration = (unsigned long long)ktime_to_ns(delta) >> 10;
|
||||
|
||||
bt_dev_info(hdev, "Device booted in %llu usecs", duration);
|
||||
|
||||
clear_bit(BTUSB_BOOTLOADER, &data->flags);
|
||||
|
||||
@ -3495,7 +3413,7 @@ static int btusb_mtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwnam
|
||||
fw_ptr = fw->data;
|
||||
fw_bin_ptr = fw_ptr;
|
||||
globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
|
||||
section_num = globaldesc->section_num;
|
||||
section_num = le32_to_cpu(globaldesc->section_num);
|
||||
|
||||
for (i = 0; i < section_num; i++) {
|
||||
first_block = 1;
|
||||
@ -3503,8 +3421,8 @@ static int btusb_mtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwnam
|
||||
sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
|
||||
MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
|
||||
|
||||
section_offset = sectionmap->secoffset;
|
||||
dl_size = sectionmap->bin_info_spec.dlsize;
|
||||
section_offset = le32_to_cpu(sectionmap->secoffset);
|
||||
dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize);
|
||||
|
||||
if (dl_size > 0) {
|
||||
retry = 20;
|
||||
@ -3740,7 +3658,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
|
||||
int err, status;
|
||||
u32 dev_id;
|
||||
char fw_bin_name[64];
|
||||
u32 fw_version;
|
||||
u32 fw_version = 0;
|
||||
u8 param;
|
||||
|
||||
calltime = ktime_get();
|
||||
|
@ -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 @@ retry:
|
||||
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);
|
||||
|
401
drivers/bluetooth/virtio_bt.c
Normal file
401
drivers/bluetooth/virtio_bt.c
Normal file
@ -0,0 +1,401 @@
|
||||
// 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)
|
||||
|
31
include/uapi/linux/virtio_bt.h
Normal file
31
include/uapi/linux/virtio_bt.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* 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
|
||||
|
35
net/bluetooth/aosp.c
Normal file
35
net/bluetooth/aosp.c
Normal file
@ -0,0 +1,35 @@
|
||||
// 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");
|
||||
}
|
16
net/bluetooth/aosp.h
Normal file
16
net/bluetooth/aosp.h
Normal file
@ -0,0 +1,16 @@
|
||||
// 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 @@ setup_failed:
|
||||
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 @@ done:
|
||||
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;
|
||||
|
||||
if (!hci_dev_test_flag(req->hdev, HCI_BREDR_ENABLED))
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
/* Update page scan state (since we may have modified it when setting
|
||||
* the event filter).
|
||||
*/
|
||||
__hci_req_update_scan(req);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
|
@ -54,7 +54,7 @@
|
||||
#define SMP_ALLOW_CMD(smp, code) set_bit(code, &smp->allow_cmd)
|
||||
|
||||
/* Keys which are not distributed with Secure Connections */
|
||||
#define SMP_SC_NO_DIST (SMP_DIST_ENC_KEY | SMP_DIST_LINK_KEY);
|
||||
#define SMP_SC_NO_DIST (SMP_DIST_ENC_KEY | SMP_DIST_LINK_KEY)
|
||||
|
||||
#define SMP_TIMEOUT msecs_to_jiffies(30000)
|
||||
|
||||
@ -398,7 +398,7 @@ static int smp_e(const u8 *k, u8 *r)
|
||||
|
||||
SMP_DBG("r %16phN", r);
|
||||
|
||||
memzero_explicit(&ctx, sizeof (ctx));
|
||||
memzero_explicit(&ctx, sizeof(ctx));
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -595,7 +595,7 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
|
||||
if (!chan)
|
||||
return;
|
||||
|
||||
BT_DBG("code 0x%2.2x", code);
|
||||
bt_dev_dbg(conn->hcon->hdev, "code 0x%2.2x", code);
|
||||
|
||||
iv[0].iov_base = &code;
|
||||
iv[0].iov_len = 1;
|
||||
@ -859,7 +859,8 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||
memset(smp->tk, 0, sizeof(smp->tk));
|
||||
clear_bit(SMP_FLAG_TK_VALID, &smp->flags);
|
||||
|
||||
BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);
|
||||
bt_dev_dbg(hcon->hdev, "auth:%d lcl:%d rem:%d", auth, local_io,
|
||||
remote_io);
|
||||
|
||||
/* If neither side wants MITM, either "just" confirm an incoming
|
||||
* request or use just-works for outgoing ones. The JUST_CFM
|
||||
@ -924,7 +925,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||
get_random_bytes(&passkey, sizeof(passkey));
|
||||
passkey %= 1000000;
|
||||
put_unaligned_le32(passkey, smp->tk);
|
||||
BT_DBG("PassKey: %d", passkey);
|
||||
bt_dev_dbg(hcon->hdev, "PassKey: %d", passkey);
|
||||
set_bit(SMP_FLAG_TK_VALID, &smp->flags);
|
||||
}
|
||||
|
||||
@ -949,7 +950,7 @@ static u8 smp_confirm(struct smp_chan *smp)
|
||||
struct smp_cmd_pairing_confirm cp;
|
||||
int ret;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(conn->hcon->hdev, "conn %p", conn);
|
||||
|
||||
ret = smp_c1(smp->tk, smp->prnd, smp->preq, smp->prsp,
|
||||
conn->hcon->init_addr_type, &conn->hcon->init_addr,
|
||||
@ -977,7 +978,8 @@ static u8 smp_random(struct smp_chan *smp)
|
||||
u8 confirm[16];
|
||||
int ret;
|
||||
|
||||
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
|
||||
bt_dev_dbg(conn->hcon->hdev, "conn %p %s", conn,
|
||||
conn->hcon->out ? "master" : "slave");
|
||||
|
||||
ret = smp_c1(smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
||||
hcon->init_addr_type, &hcon->init_addr,
|
||||
@ -1236,7 +1238,7 @@ static void smp_distribute_keys(struct smp_chan *smp)
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
__u8 *keydist;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
rsp = (void *) &smp->prsp[1];
|
||||
|
||||
@ -1266,7 +1268,7 @@ static void smp_distribute_keys(struct smp_chan *smp)
|
||||
*keydist &= ~SMP_SC_NO_DIST;
|
||||
}
|
||||
|
||||
BT_DBG("keydist 0x%x", *keydist);
|
||||
bt_dev_dbg(hdev, "keydist 0x%x", *keydist);
|
||||
|
||||
if (*keydist & SMP_DIST_ENC_KEY) {
|
||||
struct smp_cmd_encrypt_info enc;
|
||||
@ -1366,13 +1368,14 @@ static void smp_timeout(struct work_struct *work)
|
||||
security_timer.work);
|
||||
struct l2cap_conn *conn = smp->conn;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(conn->hcon->hdev, "conn %p", conn);
|
||||
|
||||
hci_disconnect(conn->hcon, HCI_ERROR_REMOTE_USER_TERM);
|
||||
}
|
||||
|
||||
static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
{
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp;
|
||||
|
||||
@ -1382,13 +1385,13 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
|
||||
smp->tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
|
||||
if (IS_ERR(smp->tfm_cmac)) {
|
||||
BT_ERR("Unable to create CMAC crypto context");
|
||||
bt_dev_err(hcon->hdev, "Unable to create CMAC crypto context");
|
||||
goto zfree_smp;
|
||||
}
|
||||
|
||||
smp->tfm_ecdh = crypto_alloc_kpp("ecdh", 0, 0);
|
||||
if (IS_ERR(smp->tfm_ecdh)) {
|
||||
BT_ERR("Unable to create ECDH crypto context");
|
||||
bt_dev_err(hcon->hdev, "Unable to create ECDH crypto context");
|
||||
goto free_shash;
|
||||
}
|
||||
|
||||
@ -1399,7 +1402,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
|
||||
INIT_DELAYED_WORK(&smp->security_timer, smp_timeout);
|
||||
|
||||
hci_conn_hold(conn->hcon);
|
||||
hci_conn_hold(hcon);
|
||||
|
||||
return smp;
|
||||
|
||||
@ -1564,7 +1567,7 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op)
|
||||
if (!hcon->out)
|
||||
return 0;
|
||||
|
||||
BT_DBG("%s Starting passkey round %u", hdev->name,
|
||||
bt_dev_dbg(hdev, "Starting passkey round %u",
|
||||
smp->passkey_round + 1);
|
||||
|
||||
SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
|
||||
@ -1625,11 +1628,11 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
|
||||
u32 value;
|
||||
int err;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
if (!conn)
|
||||
return -ENOTCONN;
|
||||
|
||||
bt_dev_dbg(conn->hcon->hdev, "");
|
||||
|
||||
chan = conn->smp;
|
||||
if (!chan)
|
||||
return -ENOTCONN;
|
||||
@ -1651,7 +1654,7 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
|
||||
case MGMT_OP_USER_PASSKEY_REPLY:
|
||||
value = le32_to_cpu(passkey);
|
||||
memset(smp->tk, 0, sizeof(smp->tk));
|
||||
BT_DBG("PassKey: %d", value);
|
||||
bt_dev_dbg(conn->hcon->hdev, "PassKey: %d", value);
|
||||
put_unaligned_le32(value, smp->tk);
|
||||
fallthrough;
|
||||
case MGMT_OP_USER_CONFIRM_REPLY:
|
||||
@ -1733,7 +1736,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
u8 key_size, auth, sec_level;
|
||||
int ret;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*req))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -1887,7 +1890,7 @@ static u8 sc_send_public_key(struct smp_chan *smp)
|
||||
}
|
||||
|
||||
if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) {
|
||||
BT_DBG("Using debug keys");
|
||||
bt_dev_dbg(hdev, "Using debug keys");
|
||||
if (set_ecdh_privkey(smp->tfm_ecdh, debug_sk))
|
||||
return SMP_UNSPECIFIED;
|
||||
memcpy(smp->local_pk, debug_pk, 64);
|
||||
@ -1924,7 +1927,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
u8 key_size, auth;
|
||||
int ret;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rsp))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -2019,7 +2022,7 @@ static u8 sc_check_confirm(struct smp_chan *smp)
|
||||
{
|
||||
struct l2cap_conn *conn = smp->conn;
|
||||
|
||||
BT_DBG("");
|
||||
bt_dev_dbg(conn->hcon->hdev, "");
|
||||
|
||||
if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
|
||||
return sc_passkey_round(smp, SMP_CMD_PAIRING_CONFIRM);
|
||||
@ -2078,8 +2081,10 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
|
||||
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
|
||||
bt_dev_dbg(hdev, "conn %p %s", conn, hcon->out ? "master" : "slave");
|
||||
|
||||
if (skb->len < sizeof(smp->pcnf))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -2094,7 +2099,7 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (test_bit(SMP_FLAG_REMOTE_PK, &smp->flags))
|
||||
return sc_check_confirm(smp);
|
||||
|
||||
BT_ERR("Unexpected SMP Pairing Confirm");
|
||||
bt_dev_err(hdev, "Unexpected SMP Pairing Confirm");
|
||||
|
||||
ret = fixup_sc_false_positive(smp);
|
||||
if (ret)
|
||||
@ -2125,7 +2130,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
u32 passkey;
|
||||
int err;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(hcon->hdev, "conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(smp->rrnd))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -2284,7 +2289,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
struct smp_chan *smp;
|
||||
u8 sec_level, auth;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rp))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -2347,7 +2352,8 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||
__u8 authreq;
|
||||
int ret;
|
||||
|
||||
BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
|
||||
bt_dev_dbg(hcon->hdev, "conn %p hcon %p level 0x%2.2x", conn, hcon,
|
||||
sec_level);
|
||||
|
||||
/* This may be NULL if there's an unexpected disconnection */
|
||||
if (!conn)
|
||||
@ -2483,7 +2489,7 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(conn->hcon->hdev, "conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rp))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -2516,7 +2522,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
struct smp_ltk *ltk;
|
||||
u8 authenticated;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rp))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -2548,7 +2554,7 @@ static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
|
||||
BT_DBG("");
|
||||
bt_dev_dbg(conn->hcon->hdev, "");
|
||||
|
||||
if (skb->len < sizeof(*info))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -2580,7 +2586,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
bdaddr_t rpa;
|
||||
|
||||
BT_DBG("");
|
||||
bt_dev_dbg(hcon->hdev, "");
|
||||
|
||||
if (skb->len < sizeof(*info))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -2647,7 +2653,7 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
struct smp_chan *smp = chan->data;
|
||||
struct smp_csrk *csrk;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(conn->hcon->hdev, "conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rp))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -2727,11 +2733,20 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
struct smp_cmd_pairing_confirm cfm;
|
||||
int err;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*key))
|
||||
return SMP_INVALID_PARAMS;
|
||||
|
||||
/* Check if remote and local public keys are the same and debug key is
|
||||
* not in use.
|
||||
*/
|
||||
if (!test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags) &&
|
||||
!crypto_memneq(key, smp->local_pk, 64)) {
|
||||
bt_dev_err(hdev, "Remote and local public keys are identical");
|
||||
return SMP_UNSPECIFIED;
|
||||
}
|
||||
|
||||
memcpy(smp->remote_pk, key, 64);
|
||||
|
||||
if (test_bit(SMP_FLAG_REMOTE_OOB, &smp->flags)) {
|
||||
@ -2782,7 +2797,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
smp->method = sc_select_method(smp);
|
||||
|
||||
BT_DBG("%s selected method 0x%02x", hdev->name, smp->method);
|
||||
bt_dev_dbg(hdev, "selected method 0x%02x", smp->method);
|
||||
|
||||
/* JUST_WORKS and JUST_CFM result in an unauthenticated key */
|
||||
if (smp->method == JUST_WORKS || smp->method == JUST_CFM)
|
||||
@ -2857,7 +2872,7 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
u8 io_cap[3], r[16], e[16];
|
||||
int err;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(hcon->hdev, "conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*check))
|
||||
return SMP_INVALID_PARAMS;
|
||||
@ -2917,7 +2932,7 @@ static int smp_cmd_keypress_notify(struct l2cap_conn *conn,
|
||||
{
|
||||
struct smp_cmd_keypress_notify *kp = (void *) skb->data;
|
||||
|
||||
BT_DBG("value 0x%02x", kp->value);
|
||||
bt_dev_dbg(conn->hcon->hdev, "value 0x%02x", kp->value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3014,7 +3029,7 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_DBG("Unknown command code 0x%2.2x", code);
|
||||
bt_dev_dbg(hcon->hdev, "Unknown command code 0x%2.2x", code);
|
||||
reason = SMP_CMD_NOTSUPP;
|
||||
goto done;
|
||||
}
|
||||
@ -3039,7 +3054,7 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
bt_dev_dbg(conn->hcon->hdev, "chan %p", chan);
|
||||
|
||||
if (chan->data)
|
||||
smp_chan_destroy(conn);
|
||||
@ -3056,7 +3071,7 @@ static void bredr_pairing(struct l2cap_chan *chan)
|
||||
struct smp_cmd_pairing req;
|
||||
struct smp_chan *smp;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
bt_dev_dbg(hdev, "chan %p", chan);
|
||||
|
||||
/* Only new pairings are interesting */
|
||||
if (!test_bit(HCI_CONN_NEW_LINK_KEY, &hcon->flags))
|
||||
@ -3103,7 +3118,7 @@ static void bredr_pairing(struct l2cap_chan *chan)
|
||||
|
||||
set_bit(SMP_FLAG_SC, &smp->flags);
|
||||
|
||||
BT_DBG("%s starting SMP over BR/EDR", hdev->name);
|
||||
bt_dev_dbg(hdev, "starting SMP over BR/EDR");
|
||||
|
||||
/* Prepare and send the BR/EDR SMP Pairing Request */
|
||||
build_bredr_pairing_cmd(smp, &req, NULL);
|
||||
@ -3121,7 +3136,7 @@ static void smp_resume_cb(struct l2cap_chan *chan)
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
bt_dev_dbg(hcon->hdev, "chan %p", chan);
|
||||
|
||||
if (hcon->type == ACL_LINK) {
|
||||
bredr_pairing(chan);
|
||||
@ -3144,7 +3159,7 @@ static void smp_ready_cb(struct l2cap_chan *chan)
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
bt_dev_dbg(hcon->hdev, "chan %p", chan);
|
||||
|
||||
/* No need to call l2cap_chan_hold() here since we already own
|
||||
* the reference taken in smp_new_conn_cb(). This is just the
|
||||
@ -3162,7 +3177,7 @@ static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
bt_dev_dbg(chan->conn->hcon->hdev, "chan %p", chan);
|
||||
|
||||
err = smp_sig_channel(chan, skb);
|
||||
if (err) {
|
||||
@ -3214,7 +3229,7 @@ static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
|
||||
{
|
||||
struct l2cap_chan *chan;
|
||||
|
||||
BT_DBG("pchan %p", pchan);
|
||||
bt_dev_dbg(pchan->conn->hcon->hdev, "pchan %p", pchan);
|
||||
|
||||
chan = l2cap_chan_create();
|
||||
if (!chan)
|
||||
@ -3235,7 +3250,7 @@ static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
|
||||
*/
|
||||
atomic_set(&chan->nesting, L2CAP_NESTING_SMP);
|
||||
|
||||
BT_DBG("created chan %p", chan);
|
||||
bt_dev_dbg(pchan->conn->hcon->hdev, "created chan %p", chan);
|
||||
|
||||
return chan;
|
||||
}
|
||||
@ -3276,14 +3291,14 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
|
||||
|
||||
tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
|
||||
if (IS_ERR(tfm_cmac)) {
|
||||
BT_ERR("Unable to create CMAC crypto context");
|
||||
bt_dev_err(hdev, "Unable to create CMAC crypto context");
|
||||
kfree_sensitive(smp);
|
||||
return ERR_CAST(tfm_cmac);
|
||||
}
|
||||
|
||||
tfm_ecdh = crypto_alloc_kpp("ecdh", 0, 0);
|
||||
if (IS_ERR(tfm_ecdh)) {
|
||||
BT_ERR("Unable to create ECDH crypto context");
|
||||
bt_dev_err(hdev, "Unable to create ECDH crypto context");
|
||||
crypto_free_shash(tfm_cmac);
|
||||
kfree_sensitive(smp);
|
||||
return ERR_CAST(tfm_ecdh);
|
||||
@ -3339,7 +3354,7 @@ static void smp_del_chan(struct l2cap_chan *chan)
|
||||
{
|
||||
struct smp_dev *smp;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
bt_dev_dbg(chan->conn->hcon->hdev, "chan %p", chan);
|
||||
|
||||
smp = chan->data;
|
||||
if (smp) {
|
||||
@ -3382,7 +3397,7 @@ int smp_register(struct hci_dev *hdev)
|
||||
{
|
||||
struct l2cap_chan *chan;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
bt_dev_dbg(hdev, "");
|
||||
|
||||
/* If the controller does not support Low Energy operation, then
|
||||
* there is also no need to register any SMP channel.
|
||||
|
Loading…
x
Reference in New Issue
Block a user