Merge tag 'for-net-next-2026-08-07' 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:

core:

 - HCI: Add support for Shorter Connection Interval (SCI) feature
 - af_bluetooth: Add minimal context analysis annotations

drivers:

 - btusb: Add ASUS USB-BT540 for Realtek 8761CU
 - btusb: Add ASUS USB-BT600 for Realtek 8761CU
 - btusb: Add USB ID 13d3:3625 for MediaTek MT7922
 - btusb: Add support for 1357:c123 Realtek 8852BE device
 - btusb: Add new VID/PID 0x0489/0xe156 for MT7902
 - btintel: Add Bluetooth SAR revision 2 support
 - btintel_pcie: Add vendor_reset PCI sysfs for PLDR
 - btnxpuart: Add M.2 Bluetooth device support using pwrseq

* tag 'for-net-next-2026-08-07' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (84 commits)
  Bluetooth: RFCOMM: take rfcomm_mutex for the deferred setup accept
  Bluetooth: MSFT: validate evt_prefix_len against the response length
  Bluetooth: ISO: zero the sockaddr before returning it in getname
  Bluetooth: ISO: do not force BT_LISTEN after a failed BIG sync
  Bluetooth: hci_sync: Disable legacy instance's ext adv before setup snapshot
  Bluetooth: hci_event: fix out-of-bounds read in LE PA report reassembly
  Bluetooth: btmtksdio: fix usage_count leak when autosuspend_delay is negative
  Bluetooth: MGMT: reject HCI_CMD_SYNC params_len above 255
  Bluetooth: btnxpuart: Add M.2 Bluetooth device support using pwrseq
  Bluetooth: MGMT: free the HCI command when it is cancelled
  Bluetooth: MGMT: free the mesh send cancel command when it is cancelled
  Bluetooth: hci_sync: free the advertising instance on the failure and cancel paths
  Bluetooth: hci_conn: fix the SCO setup context lifetime
  Bluetooth: hci_sync: Fix accept list UAF during suspend
  Bluetooth: hci_event: Use 255 as max event payload length in hci_ev_table[]
  Bluetooth: hci_event: Introduce handle_ev_vendor() for HCI_EV_VENDOR
  Bluetooth: btnxpuart: Simplify nxp_set_ind_reset() by __hci_reset_dev()
  Bluetooth: hci_core: Introduce __hci_reset_dev() with a hardware error code
  Bluetooth: coredump: Expose header size and end marker to drivers
  Bluetooth: btintel: Remove redundant (hdr->plen > 0) in btintel_recv_event()
  ...
====================

Link: https://patch.msgid.link/20260807200215.982570-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2026-08-07 15:16:53 -07:00
54 changed files with 1672 additions and 511 deletions

View File

@@ -0,0 +1,15 @@
What: /sys/bus/pci/devices/<BDF>/vendor_reset
Date: 22-Jul-2026
KernelVersion: 6.17
Contact: linux-bluetooth@vger.kernel.org
Description: This read-write attribute allows userspace to trigger a
Product Level Device Reset (PLDR) on Intel PCIe Bluetooth
controllers. Reading the attribute displays the supported
reset type. Writing integer 0 triggers PLDR. Any other
input is rejected with -EINVAL.
PLDR resets the entire on-chip platform shared between
Bluetooth and WiFi. This means any driver attached to
the WiFi device that shares hardware with this Bluetooth
device will be released, the platform will be reset, and
both the Bluetooth and WiFi devices will be re-probed.

View File

@@ -4719,6 +4719,7 @@ S: Supported
W: http://www.bluez.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
F: Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie
F: Documentation/devicetree/bindings/net/bluetooth/
F: drivers/bluetooth/

View File

@@ -50,3 +50,5 @@ hci_uart-$(CONFIG_BT_HCIUART_AG6XX) += hci_ag6xx.o
hci_uart-$(CONFIG_BT_HCIUART_MRVL) += hci_mrvl.o
hci_uart-$(CONFIG_BT_HCIUART_AML) += hci_aml.o
hci_uart-objs := $(hci_uart-y)
CONTEXT_ANALYSIS := y

View File

@@ -301,6 +301,11 @@ static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned ch
return -EILSEQ;
}
break;
default:
bt_dev_err(data->hdev, "unknown packet type 0x%02x",
pkt_type);
return -EILSEQ;
}
skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
@@ -319,6 +324,13 @@ static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned ch
}
}
if (len > skb_tailroom(data->reassembly)) {
bt_dev_err(data->hdev, "block exceeds packet length");
kfree_skb(data->reassembly);
data->reassembly = NULL;
return -EILSEQ;
}
if (len > 0)
skb_put_data(data->reassembly, buf, len);
@@ -353,6 +365,13 @@ static void bfusb_rx_complete(struct urb *urb)
skb_put(skb, count);
while (count) {
if (count < 2) {
bt_dev_err(data->hdev, "short block header");
kfree_skb(data->reassembly);
data->reassembly = NULL;
break;
}
hdr = buf[0] | (buf[1] << 8);
if (hdr & 0x4000) {
@@ -360,16 +379,28 @@ static void bfusb_rx_complete(struct urb *urb)
count -= 2;
buf += 2;
} else {
if (count < 3) {
bt_dev_err(data->hdev, "short block header");
kfree_skb(data->reassembly);
data->reassembly = NULL;
break;
}
len = (buf[2] == 0) ? 256 : buf[2];
count -= 3;
buf += 3;
}
if (count < len)
if (count < len) {
bt_dev_err(data->hdev, "block extends over URB buffer ranges");
kfree_skb(data->reassembly);
data->reassembly = NULL;
break;
}
if ((hdr & 0xe1) == 0xc1)
bfusb_recv_block(data, hdr, buf, len);
if ((hdr & 0xe1) == 0xc1 &&
bfusb_recv_block(data, hdr, buf, len) < 0)
data->hdev->stat.err_rx++;
count -= len;
buf += len;

View File

@@ -51,6 +51,7 @@ enum {
#define BTINTEL_BT_DOMAIN 0x12
#define BTINTEL_SAR_LEGACY 0
#define BTINTEL_SAR_INC_PWR 1
#define BTINTEL_SAR_REV2 2
#define BTINTEL_SAR_INC_PWR_SUPPORTED 0
#define CMD_WRITE_BOOT_PARAMS 0xfc0e
@@ -2745,9 +2746,7 @@ static u8 btintel_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb)
* based on their connection handle value range.
*/
if (iso_capable(hdev) && hci_skb_pkt_type(skb) == HCI_ACLDATA_PKT) {
__u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
if (hci_handle(handle) >= BTINTEL_ISODATA_HANDLE_BASE)
if (hci_acl_handle(skb) >= BTINTEL_ISODATA_HANDLE_BASE)
return HCI_ISODATA_PKT;
}
@@ -3104,6 +3103,111 @@ static int btintel_set_mutual_sar(struct hci_dev *hdev, struct btintel_sar_inc_p
return 0;
}
/* btintel_send_sar_rev2_band - send DDC command for one Rev2 sub-band
*
* Each DDC 0x0311-0x0316 carries 2 bytes: [ChainA_value, ChainB_value].
* cmd->len = 4 (2 id + 2 data)
* HCI total = 5 bytes (1 len + 4)
*/
static int btintel_send_sar_rev2_band(struct hci_dev *hdev,
struct btintel_cp_ddc_write *cmd,
u16 id, u8 chain_a, u8 chain_b)
{
cmd->len = 4;
cmd->id = cpu_to_le16(id);
cmd->data[0] = chain_a;
cmd->data[1] = chain_b;
return btintel_send_sar_ddc(hdev, cmd, 5);
}
static int btintel_set_sar_rev2(struct hci_dev *hdev,
struct btintel_sar_rev2 *sar)
{
struct btintel_cp_ddc_write *cmd;
struct sk_buff *skb;
u8 buffer[64];
u8 enable;
int ret;
cmd = (void *)buffer;
/* DDC 0x019e: enable/disable increased power mode SAR (1 byte) */
cmd->len = 3;
cmd->id = cpu_to_le16(0x019e);
cmd->data[0] = (sar->inc_power_mode == BTINTEL_SAR_INC_PWR_SUPPORTED) ?
0x01 : 0x00;
ret = btintel_send_sar_ddc(hdev, cmd, 4);
if (ret)
return ret;
/* DDC 0x0311-0x0316: per sub-band ChainA + ChainB limits */
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0311,
sar->chain_a.subband_2g4,
sar->chain_b.subband_2g4);
if (ret)
return ret;
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0312,
sar->chain_a.subband_5g2,
sar->chain_b.subband_5g2);
if (ret)
return ret;
/* 0x0313 and 0x0314 both carry the 5G8/5G9 value */
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0313,
sar->chain_a.subband_5g8_5g9,
sar->chain_b.subband_5g8_5g9);
if (ret)
return ret;
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0314,
sar->chain_a.subband_5g8_5g9,
sar->chain_b.subband_5g8_5g9);
if (ret)
return ret;
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0315,
sar->chain_a.subband_6g1,
sar->chain_b.subband_6g1);
if (ret)
return ret;
ret = btintel_send_sar_rev2_band(hdev, cmd, 0x0316,
sar->chain_a.subband_6g3,
sar->chain_b.subband_6g3);
if (ret)
return ret;
/* Notify firmware that SAR initialisation is complete */
enable = 0x01;
skb = __hci_cmd_sync(hdev, 0xfe25, sizeof(enable), &enable, HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_warn(hdev, "Failed to send Intel SAR Rev2 Enable (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
kfree_skb(skb);
return 0;
}
static int btintel_sar_rev2_send_to_device(struct hci_dev *hdev,
struct btintel_sar_rev2 *sar,
struct intel_version_tlv *ver)
{
u16 cnvi = ver->cnvi_top & 0xfff;
u16 cnvr = ver->cnvr_top & 0xfff;
if (cnvi < BTINTEL_CNVI_BLAZARI || cnvr != BTINTEL_CNVR_WHP2) {
bt_dev_dbg(hdev, "BT SAR Rev2 not supported on this platform (cnvi=0x%x cnvr=0x%x)",
cnvi, cnvr);
return -EOPNOTSUPP;
}
bt_dev_info(hdev, "Applying Bluetooth SAR Rev2");
return btintel_set_sar_rev2(hdev, sar);
}
static int btintel_sar_send_to_device(struct hci_dev *hdev, struct btintel_sar_inc_pwr *sar,
struct intel_version_tlv *ver)
{
@@ -3130,6 +3234,7 @@ static int btintel_acpi_set_sar(struct hci_dev *hdev, struct intel_version_tlv *
{
union acpi_object *bt_pkg, *buffer = NULL;
struct btintel_sar_inc_pwr sar;
struct btintel_sar_rev2 sar_rev2;
acpi_status status;
u8 revision;
int ret;
@@ -3150,14 +3255,96 @@ static int btintel_acpi_set_sar(struct hci_dev *hdev, struct intel_version_tlv *
goto error;
}
if (buffer->package.elements[0].type != ACPI_TYPE_INTEGER) {
bt_dev_warn(hdev, "BT_SAR: unexpected ACPI type for revision field");
ret = -EINVAL;
goto error;
}
revision = buffer->package.elements[0].integer.value;
if (revision > BTINTEL_SAR_INC_PWR) {
if (revision > BTINTEL_SAR_REV2) {
bt_dev_dbg(hdev, "BT_SAR: revision: 0x%2.2x not supported", revision);
ret = -EOPNOTSUPP;
goto error;
}
if (revision == BTINTEL_SAR_REV2 && bt_pkg->package.count == 13) {
/* Element layout: 0 = domain ID (BTINTEL_BT_DOMAIN, 0x12),
* 1 = bt_sar_bios (u32), 2 = inc_power_mode (u32),
* 3..12 = per-chain sub-band limits (u8 each).
*/
static const u64 rev2_max[13] = {
U8_MAX, /* domain ID */
U32_MAX, U32_MAX, /* bt_sar_bios, inc_power_mode */
U8_MAX, U8_MAX, U8_MAX, U8_MAX, U8_MAX, /* chain A */
U8_MAX, U8_MAX, U8_MAX, U8_MAX, U8_MAX, /* chain B */
};
union acpi_object *e;
int i;
for (i = 0; i < 13; i++) {
e = &bt_pkg->package.elements[i];
if (e->type != ACPI_TYPE_INTEGER) {
bt_dev_warn(hdev, "BT SAR Rev2: unexpected ACPI type at element %d",
i);
ret = -EINVAL;
goto error;
}
if (e->integer.value > rev2_max[i]) {
bt_dev_warn(hdev, "BT SAR Rev2: element %d value 0x%llx out of range",
i, e->integer.value);
ret = -ERANGE;
goto error;
}
}
memset(&sar_rev2, 0, sizeof(sar_rev2));
sar_rev2.revision = revision;
sar_rev2.bt_sar_bios = bt_pkg->package.elements[1].integer.value;
if (sar_rev2.bt_sar_bios != 1) {
bt_dev_warn(hdev, "Bluetooth SAR Rev2 is not enabled");
ret = -EOPNOTSUPP;
goto error;
}
sar_rev2.inc_power_mode = bt_pkg->package.elements[2].integer.value;
sar_rev2.chain_a.subband_2g4 = bt_pkg->package.elements[3].integer.value;
sar_rev2.chain_a.subband_5g2 = bt_pkg->package.elements[4].integer.value;
sar_rev2.chain_a.subband_5g8_5g9 = bt_pkg->package.elements[5].integer.value;
sar_rev2.chain_a.subband_6g1 = bt_pkg->package.elements[6].integer.value;
sar_rev2.chain_a.subband_6g3 = bt_pkg->package.elements[7].integer.value;
sar_rev2.chain_b.subband_2g4 = bt_pkg->package.elements[8].integer.value;
sar_rev2.chain_b.subband_5g2 = bt_pkg->package.elements[9].integer.value;
sar_rev2.chain_b.subband_5g8_5g9 = bt_pkg->package.elements[10].integer.value;
sar_rev2.chain_b.subband_6g1 = bt_pkg->package.elements[11].integer.value;
sar_rev2.chain_b.subband_6g3 = bt_pkg->package.elements[12].integer.value;
bt_dev_dbg(hdev, "BT SAR Rev2: revision=%u bt_sar_bios=%u inc_power_mode=%u",
sar_rev2.revision, sar_rev2.bt_sar_bios, sar_rev2.inc_power_mode);
bt_dev_dbg(hdev, "BT SAR Rev2 Chain A: 2g4=%u 5g2=%u 5g8_5g9=%u 6g1=%u 6g3=%u",
sar_rev2.chain_a.subband_2g4, sar_rev2.chain_a.subband_5g2,
sar_rev2.chain_a.subband_5g8_5g9, sar_rev2.chain_a.subband_6g1,
sar_rev2.chain_a.subband_6g3);
bt_dev_dbg(hdev, "BT SAR Rev2 Chain B: 2g4=%u 5g2=%u 5g8_5g9=%u 6g1=%u 6g3=%u",
sar_rev2.chain_b.subband_2g4, sar_rev2.chain_b.subband_5g2,
sar_rev2.chain_b.subband_5g8_5g9, sar_rev2.chain_b.subband_6g1,
sar_rev2.chain_b.subband_6g3);
ret = btintel_sar_rev2_send_to_device(hdev, &sar_rev2, ver);
goto error;
}
if (revision == BTINTEL_SAR_REV2) {
bt_dev_warn(hdev, "BT SAR Rev2: unexpected ACPI package count %d (expected 13)",
bt_pkg->package.count);
ret = -EINVAL;
goto error;
}
memset(&sar, 0, sizeof(sar));
if (revision == BTINTEL_SAR_LEGACY && bt_pkg->package.count == 8) {
@@ -3804,8 +3991,7 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
struct hci_event_hdr *hdr = (void *)skb->data;
const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };
if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
hdr->plen > 0) {
if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff) {
const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;
@@ -3834,7 +4020,7 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
/* Handle all diagnostics events separately. May still call
* hci_recv_frame.
*/
if (len >= sizeof(diagnostics_hdr) &&
if (len + 1 >= sizeof(diagnostics_hdr) &&
memcmp(&skb->data[2], diagnostics_hdr,
sizeof(diagnostics_hdr)) == 0) {
return btintel_diagnostics(hdev, skb);

View File

@@ -65,6 +65,7 @@ struct intel_tlv {
/* CNVR */
#define BTINTEL_CNVR_FMP2 0x910
#define BTINTEL_CNVR_WHP2 0xA10 /* Whale Peak2 - Panther Lake */
#define BTINTEL_IMG_BOOTLOADER 0x01 /* Bootloader image */
#define BTINTEL_IMG_IML 0x02 /* Intermediate image */
@@ -204,6 +205,23 @@ struct btintel_sar_inc_pwr {
u8 le_lr;
};
/* Bluetooth SAR feature (BRDS), Revision 2 - per-chain sub-band power limits */
struct btintel_sar_band_limits {
u8 subband_2g4;
u8 subband_5g2;
u8 subband_5g8_5g9;
u8 subband_6g1;
u8 subband_6g3;
};
struct btintel_sar_rev2 {
u8 revision;
u32 bt_sar_bios; /* 1: BIOS-managed SAR enabled */
u32 inc_power_mode; /* 0: supported, 1: disabled */
struct btintel_sar_band_limits chain_a;
struct btintel_sar_band_limits chain_b;
};
#define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8))
#define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16))
#define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff)

View File

@@ -1446,72 +1446,134 @@ static int btintel_pcie_dump_fwtrigger_event(struct btintel_pcie_data *data)
return err;
}
/* Queue a coredump dump_traces() pass.
*
* Returns true if a new coredump was queued, false if one was already
* in-flight (the BTINTEL_PCIE_COREDUMP_INPROGRESS bit serves as the
* single-writer guard for the @coredump_work item) or the workqueue is
* disabled (reset / remove in progress).
*
* Always queue this AFTER any companion event-reader work (hwexp /
* fwtrigger) so that, on the ordered @dump_workqueue, the event reader
* runs first and populates dmp_hdr.event_type / event_id before
* dump_traces consumes them.
*/
static bool btintel_pcie_queue_coredump(struct btintel_pcie_data *data,
u16 trigger_reason)
{
if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
return false;
data->dmp_hdr.trigger_reason = trigger_reason;
if (queue_work(data->dump_workqueue, &data->coredump_work))
return true;
/* Workqueue is disabled (reset/remove drained it). Release the
* guard so a later trigger, after re-probe, can succeed.
*/
clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
return false;
}
static void btintel_pcie_msix_fw_trigger_handler(struct btintel_pcie_data *data)
{
bt_dev_dbg(data->hdev, "Received firmware smart trigger cause");
if (test_and_set_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags))
/* Per-work guard: deduplicate concurrent FW-trigger interrupts.
* Cleared at the tail of btintel_pcie_fwtrigger_worker().
*/
if (test_and_set_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS,
&data->flags))
return;
/* Trigger device core dump when there is FW assert */
if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
if (!queue_work(data->dump_workqueue, &data->fwtrigger_work)) {
clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
return;
}
queue_work(data->coredump_workqueue, &data->coredump_work);
/* Queue coredump after the fwtrigger event reader so dmp_hdr.event_*
* is populated before dump_traces consumes it.
*/
btintel_pcie_queue_coredump(data, BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
}
static void btintel_pcie_msix_hw_exp_handler(struct btintel_pcie_data *data)
{
bt_dev_err(data->hdev, "Received hw exception interrupt");
/* CORE_HALTED is the single-writer guard for this handler. It is
* set once on first HW exception and cleared only by re-probe
* (data is reallocated), so it also serializes hwexp_work
* scheduling without needing a separate bit.
*/
if (test_and_set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags))
return;
if (test_and_set_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags))
return;
/* Queue companion coredump first so it is appended after hwexp_work
* on the ordered @dump_workqueue (preserves the original
* coredump-then-hwexp ordering).
*/
btintel_pcie_queue_coredump(data, BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
/* Trigger device core dump when there is HW exception */
if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
queue_work(data->coredump_workqueue, &data->coredump_work);
queue_work(data->dump_workqueue, &data->hwexp_work);
}
static void btintel_pcie_coredump_worker(struct work_struct *work)
{
struct btintel_pcie_data *data = container_of(work,
struct btintel_pcie_data, coredump_work);
int err;
/* hdev is NULL until setup_hdev() succeeds, and is cleared on
* teardown after disable_work_sync() drains us; bail in that case.
*/
if (!data->hdev)
goto out;
btintel_pcie_dump_traces(data->hdev);
out:
/* Release guard last so a new trigger can run only after this
* pass has fully completed (including dev_coredumpv()).
*/
clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
}
static void btintel_pcie_hwexp_worker(struct work_struct *work)
{
struct btintel_pcie_data *data = container_of(work,
struct btintel_pcie_data, hwexp_work);
if (!data->hdev)
return;
if (test_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags)) {
err = btintel_pcie_dump_fwtrigger_event(data);
if (err)
bt_dev_warn(data->hdev, "failed to log fwtrigger event");
clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
}
/* Unlike usb products, controller will not send hardware exception
* event on exception. Instead controller writes the hardware event
* to device memory along with optional debug events, raises MSIX
* and halts. Driver shall read the exception event from device
* memory and passes it to the stack for further processing.
*
* Re-entry is gated by BTINTEL_PCIE_CORE_HALTED in the IRQ
* handler, which is only cleared by re-probe; no per-work bit
* is needed here.
*/
btintel_pcie_read_hwexp(data);
}
if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) {
btintel_pcie_dump_traces(data->hdev);
clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
}
static void btintel_pcie_fwtrigger_worker(struct work_struct *work)
{
struct btintel_pcie_data *data = container_of(work,
struct btintel_pcie_data, fwtrigger_work);
int err;
if (test_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags)) {
/* Unlike usb products, controller will not send hardware
* exception event on exception. Instead controller writes the
* hardware event to device memory along with optional debug
* events, raises MSIX and halts. Driver shall read the
* exception event from device memory and passes it stack for
* further processing.
*/
btintel_pcie_read_hwexp(data);
clear_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags);
}
if (!data->hdev)
goto out;
err = btintel_pcie_dump_fwtrigger_event(data);
if (err)
bt_dev_warn(data->hdev, "failed to log fwtrigger event");
out:
/* Release guard last; matches set in fw_trigger handler. */
clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
}
static void btintel_pcie_rx_work(struct work_struct *work)
@@ -2363,7 +2425,6 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev)
INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
err = -EINVAL;
goto exit_error;
break;
}
data->dmp_hdr.cnvi_top = ver_tlv.cnvi_top;
@@ -2488,8 +2549,6 @@ static void btintel_pcie_inc_recovery_count(struct pci_dev *pdev,
}
}
static void btintel_pcie_reset(struct hci_dev *hdev);
static int btintel_pcie_acpi_reset_method(struct btintel_pcie_data *data)
{
union acpi_object *obj, argv4;
@@ -2650,20 +2709,22 @@ static void btintel_pcie_reset_work(struct work_struct *wk)
btintel_pcie_synchronize_irqs(data);
flush_work(&data->rx_work);
/* Drain any in-flight coredump and block new ones across reset.
* Safe from self-deadlock: coredump_work runs on a separate wq.
/* Drain any in-flight dump workers and block new ones across reset.
* Safe from self-deadlock: they all run on a separate wq.
*/
disable_work_sync(&data->coredump_work);
disable_work_sync(&data->hwexp_work);
disable_work_sync(&data->fwtrigger_work);
bt_dev_dbg(data->hdev, "Release bluetooth interface");
/* Both reset paths follow the same contract: on success they
* destroy 'data' via device_reprobe() (a fresh probe re-INIT_WORKs
* the coredump_work with disable count 0), so enable_work() must
* the dump workers with disable count 0), so enable_work() must
* NOT be called on the success path. Only the FLR path can fail
* with 'data' still alive, in which case we balance the
* disable_work_sync() above so a later successful reset is not
* permanently blocked.
* disable_work_sync() calls above so a later successful reset is
* not permanently blocked.
*
* pci_lock_rescan_remove() (held above) serializes against PCI
* device addition/removal (hotplug), so no device can be added to
@@ -2674,64 +2735,134 @@ static void btintel_pcie_reset_work(struct work_struct *wk)
goto out;
}
if (btintel_pcie_perform_flr(data))
if (btintel_pcie_perform_flr(data)) {
enable_work(&data->coredump_work);
enable_work(&data->hwexp_work);
enable_work(&data->fwtrigger_work);
}
out:
pci_dev_put(pdev);
pci_unlock_rescan_remove();
}
static void btintel_pcie_reset(struct hci_dev *hdev)
/* Schedule a device reset of the requested type.
*
* BTINTEL_PCIE_RECOVERY_IN_PROGRESS serializes all reset requesters
* (sysfs reset attribute, hci_cmd_timeout(), hw_error, resume error
* path, etc.) so that:
*
* - dev_data->reset_type is written by exactly one caller (the
* thread that wins test_and_set_bit), eliminating the race where
* a second hw_error could clobber an already-scheduled reset's
* type;
* - the write happens AFTER the bit is set, so reset_work observes
* it through schedule_work()'s memory ordering;
* - losers return without touching reset_type or scheduling the
* work, so concurrent triggers are silently coalesced into the
* in-flight one (whose recovery will reinitialize the device
* regardless of the dropped trigger's variant).
*
* The bit is cleared only by .remove() / re-probe via fresh devm
* allocation, which is the intended one-shot semantics: a reset
* tears down and re-probes 'data', so there is no "in-flight"
* reset to follow up after device_reprobe() succeeds.
*/
static void btintel_pcie_request_reset(struct btintel_pcie_data *data,
enum btintel_pcie_reset_type type)
{
struct btintel_pcie_data *data;
data = hci_get_drvdata(hdev);
if (!test_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags))
return;
if (test_and_set_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags))
return;
data->reset_type = type;
pci_dev_get(data->pdev);
schedule_work(&data->reset_work);
}
static void btintel_pcie_hci_reset(struct hci_dev *hdev)
{
struct btintel_pcie_data *data = hci_get_drvdata(hdev);
btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR);
}
static ssize_t vendor_reset_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int val;
struct pci_dev *pdev = to_pci_dev(dev);
struct btintel_pcie_data *data = pci_get_drvdata(pdev);
if (!data || !data->hdev)
return -ENODEV;
if (kstrtouint(buf, 10, &val) || val != 0) {
bt_dev_warn(data->hdev, "PLDR rejected: invalid input");
return -EINVAL;
}
bt_dev_info(data->hdev, "PLDR triggered via sysfs");
btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_PLDR);
return count;
}
static ssize_t vendor_reset_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sysfs_emit(buf, "0 - PLDR\n");
}
static DEVICE_ATTR_RW(vendor_reset);
static struct attribute *btintel_pcie_attrs[] = {
&dev_attr_vendor_reset.attr,
NULL,
};
ATTRIBUTE_GROUPS(btintel_pcie);
static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code)
{
struct btintel_pcie_dev_recovery *data;
struct btintel_pcie_dev_recovery *rec;
struct btintel_pcie_data *dev_data = hci_get_drvdata(hdev);
struct pci_dev *pdev = dev_data->pdev;
enum btintel_pcie_reset_type type;
time64_t retry_window;
if (test_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &dev_data->flags))
return;
btintel_pcie_dump_debug_registers(hdev);
data = btintel_pcie_get_recovery(pdev, &hdev->dev);
if (!data)
rec = btintel_pcie_get_recovery(pdev, &hdev->dev);
if (!rec)
return;
if (code == 0x13)
dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_PLDR;
else
dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR;
type = (code == 0x13) ? BTINTEL_PCIE_IOSF_PRR_PLDR
: BTINTEL_PCIE_IOSF_PRR_FLR;
bt_dev_err(hdev, "Encountered exception err:0x%x triggering: %s", code,
dev_data->reset_type == BTINTEL_PCIE_IOSF_PRR_PLDR ? "PLDR" : "FLR");
retry_window = ktime_get_boottime_seconds() - data->last_error;
type == BTINTEL_PCIE_IOSF_PRR_PLDR ? "PLDR" : "FLR");
retry_window = ktime_get_boottime_seconds() - rec->last_error;
if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS &&
data->count >= BTINTEL_PCIE_FLR_MAX_RETRY) {
rec->count >= BTINTEL_PCIE_FLR_MAX_RETRY) {
bt_dev_err(hdev, "Exhausted maximum: %d recovery attempts: %d",
BTINTEL_PCIE_FLR_MAX_RETRY, data->count);
BTINTEL_PCIE_FLR_MAX_RETRY, rec->count);
bt_dev_dbg(hdev, "Boot time: %lld seconds",
ktime_get_boottime_seconds());
bt_dev_dbg(hdev, "last error at: %lld seconds",
data->last_error);
rec->last_error);
return;
}
btintel_pcie_inc_recovery_count(pdev, &hdev->dev);
btintel_pcie_reset(hdev);
btintel_pcie_request_reset(dev_data, type);
}
static bool btintel_pcie_wakeup(struct hci_dev *hdev)
@@ -2821,7 +2952,7 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
hdev->hw_error = btintel_pcie_hw_error;
hdev->set_diag = btintel_set_diag;
hdev->set_bdaddr = btintel_set_bdaddr;
hdev->reset = btintel_pcie_reset;
hdev->reset = btintel_pcie_hci_reset;
hdev->wakeup = btintel_pcie_wakeup;
hdev->hci_drv = &btintel_pcie_hci_drv;
@@ -2869,8 +3000,8 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
if (!data->workqueue)
return -ENOMEM;
data->coredump_workqueue = alloc_ordered_workqueue(KBUILD_MODNAME "_cd", 0);
if (!data->coredump_workqueue) {
data->dump_workqueue = alloc_ordered_workqueue(KBUILD_MODNAME "_cd", 0);
if (!data->dump_workqueue) {
destroy_workqueue(data->workqueue);
return -ENOMEM;
}
@@ -2879,6 +3010,8 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
INIT_WORK(&data->rx_work, btintel_pcie_rx_work);
INIT_WORK(&data->reset_work, btintel_pcie_reset_work);
INIT_WORK(&data->coredump_work, btintel_pcie_coredump_worker);
INIT_WORK(&data->hwexp_work, btintel_pcie_hwexp_worker);
INIT_WORK(&data->fwtrigger_work, btintel_pcie_fwtrigger_worker);
data->boot_stage_cache = 0x00;
data->img_resp_cache = 0x00;
@@ -2921,7 +3054,7 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
/* reset device before exit */
btintel_pcie_reset_bt(data);
destroy_workqueue(data->coredump_workqueue);
destroy_workqueue(data->dump_workqueue);
pci_clear_master(pdev);
@@ -2940,12 +3073,14 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
return;
}
/* Permanently block coredump triggers and drain the worker before
* tearing down. Must run before cancel_work_sync(&reset_work) so
* the disable counter stays >= 1 even after reset_work()'s
/* Permanently block all dump triggers and drain the workers before
* tearing down. Must run before disable_work_sync(&reset_work) so
* the disable counters stay >= 1 even after reset_work()'s
* balanced enable_work() (counter 2 -> 1, never reaching 0).
*/
disable_work_sync(&data->coredump_work);
disable_work_sync(&data->hwexp_work);
disable_work_sync(&data->fwtrigger_work);
/* Cancel pending reset work. Skip only when remove() is called from
* within the reset work itself (PLDR device_reprobe path) to avoid
@@ -2973,7 +3108,7 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
btintel_pcie_release_hdev(data);
destroy_workqueue(data->coredump_workqueue);
destroy_workqueue(data->dump_workqueue);
destroy_workqueue(data->workqueue);
btintel_pcie_free(data);
@@ -2992,16 +3127,8 @@ static void btintel_pcie_coredump(struct device *dev)
if (!data)
return;
if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
return;
data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER;
/* queue_work() returns false if the work is disabled (reset or
* remove in progress); clear the in-progress bit so a later
* trigger can succeed once the work is re-enabled.
*/
if (!queue_work(data->coredump_workqueue, &data->coredump_work))
clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
btintel_pcie_queue_coredump(data,
BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER);
}
#endif
@@ -3113,8 +3240,7 @@ static int btintel_pcie_resume(struct device *dev)
if (data->pm_sx_event == PM_EVENT_FREEZE ||
data->pm_sx_event == PM_EVENT_HIBERNATE) {
set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR;
btintel_pcie_reset(data->hdev);
btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR);
return 0;
}
@@ -3138,14 +3264,10 @@ static int btintel_pcie_resume(struct device *dev)
if (btintel_pcie_in_error(data) ||
btintel_pcie_in_device_halt(data)) {
bt_dev_err(data->hdev, "Controller in error state for D0 entry");
if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS,
&data->flags)) {
data->dmp_hdr.trigger_reason =
BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
queue_work(data->coredump_workqueue, &data->coredump_work);
}
btintel_pcie_queue_coredump(data,
BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
btintel_pcie_reset(data->hdev);
btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR);
}
return err;
}
@@ -3165,6 +3287,7 @@ static struct pci_driver btintel_pcie_driver = {
.probe = btintel_pcie_probe,
.remove = btintel_pcie_remove,
.driver.pm = pm_sleep_ptr(&btintel_pcie_pm_ops),
.dev_groups = btintel_pcie_groups,
#ifdef CONFIG_DEV_COREDUMP
.driver.coredump = btintel_pcie_coredump
#endif

View File

@@ -118,7 +118,6 @@ enum {
enum {
BTINTEL_PCIE_CORE_HALTED,
BTINTEL_PCIE_HWEXP_INPROGRESS,
BTINTEL_PCIE_COREDUMP_INPROGRESS,
BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS,
BTINTEL_PCIE_RECOVERY_IN_PROGRESS,
@@ -466,8 +465,11 @@ struct btintel_pcie_dump_header {
* @workqueue: workqueue for RX work
* @rx_skb_q: SKB queue for RX packet
* @rx_work: RX work struct to process the RX packet in @rx_skb_q
* @coredump_workqueue: dedicated workqueue for coredump collection
* @coredump_work: work struct for coredump trace collection
* @dump_workqueue: dedicated ordered workqueue serializing the coredump,
* hardware exception, and firmware-trigger dump workers
* @coredump_work: work struct for DRAM trace coredump collection
* @hwexp_work: work struct for hardware exception event read
* @fwtrigger_work: work struct for firmware-triggered diagnostic event read
* @dma_pool: DMA pool for descriptors, index array and ci
* @dma_p_addr: DMA address for pool
* @dma_v_addr: address of pool
@@ -516,8 +518,10 @@ struct btintel_pcie_data {
struct work_struct rx_work;
struct work_struct reset_work;
struct workqueue_struct *coredump_workqueue;
struct workqueue_struct *dump_workqueue;
struct work_struct coredump_work;
struct work_struct hwexp_work;
struct work_struct fwtrigger_work;
struct dma_pool *dma_pool;
dma_addr_t dma_p_addr;

View File

@@ -43,10 +43,17 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
{
struct hci_event_hdr *hdr = (void *) skb->data;
if (skb->len < sizeof(*hdr))
return true;
if (hdr->evt == HCI_EV_CMD_COMPLETE) {
struct hci_ev_cmd_complete *ec;
u16 opcode;
if (hdr->plen < sizeof(*ec) ||
skb->len < HCI_EVENT_HDR_SIZE + sizeof(*ec))
return true;
ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE);
opcode = __le16_to_cpu(ec->opcode);
@@ -74,6 +81,9 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
struct btmrvl_event *event;
int ret = 0;
if (skb->len <= offsetof(typeof(*event), data[0]))
return -EINVAL;
event = (struct btmrvl_event *) skb->data;
if (event->ec != 0xff) {
BT_DBG("Not Marvell Event=%x", event->ec);
@@ -83,6 +93,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
switch (event->data[0]) {
case BT_EVENT_AUTO_SLEEP_MODE:
if (skb->len <= offsetof(typeof(*event), data[2]))
return -EINVAL;
if (!event->data[2]) {
if (event->data[1] == BT_PS_ENABLE)
adapter->psmode = 1;
@@ -96,6 +108,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
break;
case BT_EVENT_HOST_SLEEP_CONFIG:
if (skb->len <= offsetof(typeof(*event), data[3]))
return -EINVAL;
if (!event->data[3])
BT_DBG("gpio=%x, gap=%x", event->data[1],
event->data[2]);
@@ -104,6 +118,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
break;
case BT_EVENT_HOST_SLEEP_ENABLE:
if (skb->len <= offsetof(typeof(*event), data[1]))
return -EINVAL;
if (!event->data[1]) {
adapter->hs_state = HS_ACTIVATED;
if (adapter->psmode)
@@ -116,6 +132,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
break;
case BT_EVENT_MODULE_CFG_REQ:
if (skb->len <= offsetof(typeof(*event), data[2]))
return -EINVAL;
if (priv->btmrvl_dev.sendcmdflag &&
event->data[1] == MODULE_BRINGUP_REQ) {
BT_DBG("EVENT:%s",
@@ -133,6 +151,8 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
break;
case BT_EVENT_POWER_STATE:
if (skb->len <= offsetof(typeof(*event), data[1]))
return -EINVAL;
if (event->data[1] == BT_PS_SLEEP)
adapter->ps_state = PS_SLEEP;
BT_DBG("EVENT:%s",

View File

@@ -799,7 +799,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
skb_pull(skb, SDIO_HEADER_LEN);
if (btmrvl_process_event(priv, skb))
hci_recv_frame(hdev, skb);
kfree_skb(skb);
hdev->stat.byte_rx += buf_len;
break;

View File

@@ -1480,6 +1480,9 @@ static void btmtksdio_remove(struct sdio_func *func)
if (test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
btmtksdio_close(hdev);
if (bdev->data->pm_runtime_supported)
pm_runtime_dont_use_autosuspend(bdev->dev);
/* Be consistent the state in btmtksdio_probe */
pm_runtime_get_noresume(bdev->dev);

View File

@@ -9,6 +9,8 @@
#include <linux/serdev.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/pwrseq/consumer.h>
#include <linux/skbuff.h>
#include <linux/unaligned.h>
#include <linux/firmware.h>
@@ -211,6 +213,7 @@ struct btnxpuart_dev {
struct ps_data psdata;
struct btnxpuart_data *nxp_data;
struct pwrseq_desc *pwrseq;
struct reset_control *pdn;
struct hci_uart hu;
};
@@ -1331,19 +1334,7 @@ static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
{
static const u8 ir_hw_err[] = { HCI_EV_HARDWARE_ERROR,
0x01, BTNXPUART_IR_HW_ERR };
struct sk_buff *skb;
skb = bt_skb_alloc(3, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
skb_put_data(skb, ir_hw_err, 3);
/* Inject Hardware Error to upper stack */
return hci_recv_frame(hdev, skb);
return __hci_reset_dev(hdev, BTNXPUART_IR_HW_ERR);
}
/* Firmware dump */
@@ -1872,11 +1863,26 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
return err;
}
if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) {
struct pwrseq_desc *pwrseq;
pwrseq = pwrseq_get(&serdev->ctrl->dev, "uart");
if (IS_ERR(pwrseq))
return dev_err_probe(&serdev->dev, PTR_ERR(pwrseq),
"failed to get pwrseq\n");
nxpdev->pwrseq = pwrseq;
err = pwrseq_power_on(pwrseq);
if (err)
goto err_pwrseq_put;
}
/* Initialize and register HCI device */
hdev = hci_alloc_dev();
if (!hdev) {
dev_err(&serdev->dev, "Can't allocate HCI device\n");
return -ENOMEM;
err = -ENOMEM;
goto err_pwrseq_put;
}
reset_control_deassert(nxpdev->pdn);
@@ -1907,23 +1913,31 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
if (bacmp(&ba, BDADDR_ANY))
hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_PROPERTY);
if (hci_register_dev(hdev) < 0) {
err = hci_register_dev(hdev);
if (err < 0) {
dev_err(&serdev->dev, "Can't register HCI device\n");
goto probe_fail;
}
if (ps_setup(hdev))
goto probe_fail;
if (ps_setup(hdev)) {
err = -ENODEV;
goto probe_fail_unregister;
}
hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr,
nxp_coredump_notify);
return 0;
probe_fail_unregister:
hci_unregister_dev(hdev);
probe_fail:
reset_control_assert(nxpdev->pdn);
hci_free_dev(hdev);
return -ENODEV;
err_pwrseq_put:
if (nxpdev->pwrseq)
pwrseq_put(nxpdev->pwrseq);
return err;
}
static void nxp_serdev_remove(struct serdev_device *serdev)
@@ -1950,6 +1964,8 @@ static void nxp_serdev_remove(struct serdev_device *serdev)
ps_cleanup(nxpdev);
hci_unregister_dev(hdev);
reset_control_assert(nxpdev->pdn);
if (nxpdev->pwrseq)
pwrseq_put(nxpdev->pwrseq);
hci_free_dev(hdev);
}

View File

@@ -190,25 +190,6 @@ static int qca_send_patch_config_cmd(struct hci_dev *hdev)
return err;
}
static int qca_send_reset(struct hci_dev *hdev)
{
struct sk_buff *skb;
int err;
bt_dev_dbg(hdev, "QCA HCI_RESET");
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(hdev, "QCA Reset failed (%d)", err);
return err;
}
kfree_skb(skb);
return 0;
}
static int qca_read_fw_board_id(struct hci_dev *hdev, u16 *bid)
{
u8 cmd;
@@ -990,11 +971,12 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
}
/* Perform HCI reset */
err = qca_send_reset(hdev);
err = __hci_reset_sync(hdev);
if (err < 0) {
bt_dev_err(hdev, "QCA Failed to run HCI_RESET (%d)", err);
return err;
}
bt_dev_dbg(hdev, "QCA HCI_RESET succeed");
switch (soc_type) {
case QCA_WCN3991:
@@ -1029,8 +1011,7 @@ int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
baswap(&bdaddr_swapped, bdaddr);
skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6,
&bdaddr_swapped, HCI_EV_VENDOR,
HCI_INIT_TIMEOUT);
&bdaddr_swapped, 0, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err);

View File

@@ -107,7 +107,6 @@ static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
return -ENOMEM;
h_adapter->priv = priv;
ops->set_bt_context(priv, h_adapter);
h_adapter->proto_ops = ops;
hdev = hci_alloc_dev();
@@ -136,6 +135,8 @@ static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops)
goto err;
}
ops->set_bt_context(priv, h_adapter);
return 0;
err:
h_adapter->hdev = NULL;

View File

@@ -297,6 +297,8 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3503), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
/* QCA WCN6855 chipset */
{ USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 |
@@ -679,6 +681,8 @@ static const struct usb_device_id quirks_table[] = {
{ USB_DEVICE(0x13d3, 0x3606), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
/* MediaTek MT7902 Bluetooth devices */
{ USB_DEVICE(0x0489, 0xe156), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0e8d, 0x1ede), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3579), .driver_info = BTUSB_MEDIATEK |
@@ -796,6 +800,8 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3613), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3625), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3627), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3628), .driver_info = BTUSB_MEDIATEK |
@@ -850,6 +856,12 @@ static const struct usb_device_id quirks_table[] = {
{ USB_DEVICE(0x37ad, 0x0600), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Additional Realtek 8761CU Bluetooth devices */
{ USB_DEVICE(0x0b05, 0x1bef), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0b05, 0x1d70), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Additional Realtek 8821AE Bluetooth devices */
{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK },
@@ -882,6 +894,8 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0bda, 0xc123), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x1357, 0xc123), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0cb5, 0xc547), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
@@ -937,6 +951,10 @@ struct qca_dump_info {
u16 ram_dump_seqno;
};
struct btqca_data {
struct qca_dump_info qca_dump;
};
#define BTUSB_MAX_ISOC_FRAMES 10
#define BTUSB_INTR_RUNNING 0
@@ -1010,6 +1028,7 @@ struct btusb_data {
bool usb_alt6_packet_flow;
int isoc_altsetting;
int suspend_count;
const struct usb_device_id *match_id;
int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
int (*recv_acl)(struct hci_dev *hdev, struct sk_buff *skb);
@@ -1022,8 +1041,6 @@ struct btusb_data {
int (*disconnect)(struct hci_dev *hdev);
int oob_wake_irq; /* irq for out-of-band wake-on-bt */
struct qca_dump_info qca_dump;
};
static void btusb_reset(struct hci_dev *hdev)
@@ -1235,14 +1252,16 @@ static inline void btusb_free_frags(struct btusb_data *data)
spin_unlock_irqrestore(&data->rxlock, flags);
}
static int btusb_recv_event(struct btusb_data *data, struct sk_buff *skb)
static int btusb_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
if (data->intr_interval) {
/* Trigger dequeue immediately if an event is received */
schedule_delayed_work(&data->rx_work, 0);
}
return data->recv_event(data->hdev, skb);
return data->recv_event(hdev, skb);
}
static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
@@ -1302,7 +1321,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
}
/* Complete frame */
btusb_recv_event(data, skb);
btusb_recv_event(data->hdev, skb);
skb = NULL;
}
}
@@ -1313,13 +1332,15 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
return err;
}
static int btusb_recv_acl(struct btusb_data *data, struct sk_buff *skb)
static int btusb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
/* Only queue ACL packet if intr_interval is set as it means
* force_poll_sync has been enabled.
*/
if (!data->intr_interval)
return data->recv_acl(data->hdev, skb);
return data->recv_acl(hdev, skb);
skb_queue_tail(&data->acl_q, skb);
schedule_delayed_work(&data->rx_work, data->intr_interval);
@@ -1358,10 +1379,8 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
hci_skb_expect(skb) -= len;
if (skb->len == HCI_ACL_HDR_SIZE) {
__le16 dlen = hci_acl_hdr(skb)->dlen;
/* Complete ACL header */
hci_skb_expect(skb) = __le16_to_cpu(dlen);
hci_skb_expect(skb) = hci_acl_dlen(skb);
if (skb_tailroom(skb) < hci_skb_expect(skb)) {
kfree_skb(skb);
@@ -1374,7 +1393,7 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
if (!hci_skb_expect(skb)) {
/* Complete frame */
btusb_recv_acl(data, skb);
btusb_recv_acl(data->hdev, skb);
skb = NULL;
}
}
@@ -2053,6 +2072,14 @@ static void btusb_stop_traffic(struct btusb_data *data)
usb_kill_anchored_urbs(&data->ctrl_anchor);
}
static void btusb_prepare_reset(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
}
static int btusb_close(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
@@ -2783,7 +2810,7 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
{
if (skb->len >= HCI_EVENT_HDR_SIZE + 1 &&
skb->data[0] == HCI_VENDOR_PKT &&
skb->data[0] == HCI_EV_VENDOR &&
skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
struct rtk_dev_coredump_hdr hdr = {
.code = RTK_DEVCOREDUMP_CODE_MEMDUMP,
@@ -2897,8 +2924,7 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
/* Release MediaTek ISO data interface */
btusb_mtk_release_iso_intf(hdev);
btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
btusb_prepare_reset(hdev);
/* Toggle the hard reset line. The MediaTek device is going to
* yank itself off the USB and then replug. The cleanup is handled
@@ -3072,14 +3098,15 @@ static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
static int btusb_set_bdaddr_wcn6855(struct hci_dev *hdev,
const bdaddr_t *bdaddr)
{
bdaddr_t bdaddr_swapped;
struct sk_buff *skb;
u8 buf[6];
long ret;
memcpy(buf, bdaddr, sizeof(bdaddr_t));
baswap(&bdaddr_swapped, bdaddr);
skb = __hci_cmd_sync_ev(hdev, 0xfc14, sizeof(buf), buf,
HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
skb = __hci_cmd_sync_ev(hdev, 0xfc14, sizeof(bdaddr_swapped),
&bdaddr_swapped, HCI_EV_CMD_COMPLETE,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
bt_dev_err(hdev, "Change address command failed (%ld)", ret);
@@ -3115,14 +3142,15 @@ struct qca_dump_hdr {
static void btusb_dump_hdr_qca(struct hci_dev *hdev, struct sk_buff *skb)
{
char buf[128];
struct btusb_data *btdata = hci_get_drvdata(hdev);
struct btqca_data *btqca_data = hci_get_priv(hdev);
struct qca_dump_info *qca_dump_ptr = &btqca_data->qca_dump;
snprintf(buf, sizeof(buf), "Controller Name: 0x%x\n",
btdata->qca_dump.controller_id);
qca_dump_ptr->controller_id);
skb_put_data(skb, buf, strlen(buf));
snprintf(buf, sizeof(buf), "Firmware Version: 0x%x\n",
btdata->qca_dump.fw_version);
qca_dump_ptr->fw_version);
skb_put_data(skb, buf, strlen(buf));
snprintf(buf, sizeof(buf), "Driver: %s\nVendor: qca\n",
@@ -3130,7 +3158,7 @@ static void btusb_dump_hdr_qca(struct hci_dev *hdev, struct sk_buff *skb)
skb_put_data(skb, buf, strlen(buf));
snprintf(buf, sizeof(buf), "VID: 0x%x\nPID:0x%x\n",
btdata->qca_dump.id_vendor, btdata->qca_dump.id_product);
qca_dump_ptr->id_vendor, qca_dump_ptr->id_product);
skb_put_data(skb, buf, strlen(buf));
snprintf(buf, sizeof(buf), "Lmp Subversion: 0x%x\n",
@@ -3159,6 +3187,8 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
struct qca_dump_hdr *dump_hdr;
struct btusb_data *btdata = hci_get_drvdata(hdev);
struct btqca_data *btqca_data = hci_get_priv(hdev);
struct qca_dump_info *qca_dump_ptr = &btqca_data->qca_dump;
struct usb_device *udev = btdata->udev;
pkt_type = hci_skb_pkt_type(skb);
@@ -3186,8 +3216,8 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
goto out;
}
btdata->qca_dump.ram_dump_size = dump_size;
btdata->qca_dump.ram_dump_seqno = 0;
qca_dump_ptr->ram_dump_size = dump_size;
qca_dump_ptr->ram_dump_seqno = 0;
skb_pull(skb, offsetof(struct qca_dump_hdr, data0));
@@ -3199,29 +3229,29 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
skb_pull(skb, offsetof(struct qca_dump_hdr, data));
}
if (!btdata->qca_dump.ram_dump_size) {
if (!qca_dump_ptr->ram_dump_size) {
ret = -EINVAL;
bt_dev_err(hdev, "memdump is not active");
goto out;
}
if ((seqno > btdata->qca_dump.ram_dump_seqno + 1) && (seqno != QCA_LAST_SEQUENCE_NUM)) {
dump_size = QCA_MEMDUMP_PKT_SIZE * (seqno - btdata->qca_dump.ram_dump_seqno - 1);
if ((seqno > qca_dump_ptr->ram_dump_seqno + 1) && seqno != QCA_LAST_SEQUENCE_NUM) {
dump_size = QCA_MEMDUMP_PKT_SIZE * (seqno - qca_dump_ptr->ram_dump_seqno - 1);
hci_devcd_append_pattern(hdev, 0x0, dump_size);
bt_dev_err(hdev,
"expected memdump seqno(%u) is not received(%u)\n",
btdata->qca_dump.ram_dump_seqno, seqno);
btdata->qca_dump.ram_dump_seqno = seqno;
qca_dump_ptr->ram_dump_seqno, seqno);
qca_dump_ptr->ram_dump_seqno = seqno;
kfree_skb(skb);
return ret;
}
hci_devcd_append(hdev, skb);
btdata->qca_dump.ram_dump_seqno++;
qca_dump_ptr->ram_dump_seqno++;
if (seqno == QCA_LAST_SEQUENCE_NUM) {
bt_dev_info(hdev,
"memdump done: pkts(%u), total(%u)\n",
btdata->qca_dump.ram_dump_seqno, btdata->qca_dump.ram_dump_size);
qca_dump_ptr->ram_dump_seqno, qca_dump_ptr->ram_dump_size);
hci_devcd_complete(hdev);
goto out;
@@ -3229,10 +3259,10 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
return ret;
out:
if (btdata->qca_dump.ram_dump_size)
if (qca_dump_ptr->ram_dump_size)
usb_enable_autosuspend(udev);
btdata->qca_dump.ram_dump_size = 0;
btdata->qca_dump.ram_dump_seqno = 0;
qca_dump_ptr->ram_dump_size = 0;
qca_dump_ptr->ram_dump_seqno = 0;
clear_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags);
if (ret < 0)
@@ -3257,7 +3287,7 @@ static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
goto out;
event_hdr = skb_pull_data(clone, sizeof(*event_hdr));
if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT))
if (!event_hdr || event_hdr->evt != HCI_EV_VENDOR)
goto out;
dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr));
@@ -3283,7 +3313,7 @@ static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
return false;
event_hdr = skb_pull_data(clone, sizeof(*event_hdr));
if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT))
if (!event_hdr || event_hdr->evt != HCI_EV_VENDOR)
goto out;
dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr));
@@ -3695,8 +3725,12 @@ static int btusb_setup_qca(struct hci_dev *hdev)
if (err)
return err;
btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
btdata->qca_dump.controller_id = le32_to_cpu(ver.rom_version);
if (btdata->match_id->driver_info & BTUSB_QCA_WCN6855) {
struct btqca_data *btqca_data = hci_get_priv(hdev);
btqca_data->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
btqca_data->qca_dump.controller_id = le32_to_cpu(ver.rom_version);
}
if (!(status & QCA_SYSCFG_UPDATED)) {
err = btusb_setup_qca_load_nvm(hdev, &ver, info);
@@ -3877,16 +3911,13 @@ static bool btusb_wakeup(struct hci_dev *hdev)
static int btusb_shutdown_qca(struct hci_dev *hdev)
{
struct sk_buff *skb;
int err;
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = __hci_reset_sync(hdev);
if (err)
bt_dev_err(hdev, "HCI reset during shutdown failed");
return PTR_ERR(skb);
}
kfree_skb(skb);
return 0;
return err;
}
static ssize_t force_poll_sync_read(struct file *file, char __user *user_buf,
@@ -4070,7 +4101,7 @@ static int btusb_probe(struct usb_interface *intf,
struct btusb_data *data;
struct hci_dev *hdev;
unsigned ifnum_base;
int err, priv_size;
int err, priv_size = 0;
BT_DBG("intf %p id %p", intf, id);
@@ -4089,7 +4120,7 @@ static int btusb_probe(struct usb_interface *intf,
id = match;
}
if (id->driver_info == BTUSB_IGNORE)
if (id->driver_info & BTUSB_IGNORE)
return -ENODEV;
if (id->driver_info & BTUSB_ATH3012) {
@@ -4107,6 +4138,7 @@ static int btusb_probe(struct usb_interface *intf,
if (!data)
return -ENOMEM;
data->match_id = id;
err = usb_find_common_endpoints(intf->cur_altsetting, &data->bulk_rx_ep,
&data->bulk_tx_ep, &data->intr_ep, NULL);
if (err)
@@ -4140,8 +4172,6 @@ static int btusb_probe(struct usb_interface *intf,
init_usb_anchor(&data->ctrl_anchor);
spin_lock_init(&data->rxlock);
priv_size = 0;
data->recv_event = hci_recv_frame;
data->recv_bulk = btusb_recv_bulk;
@@ -4160,6 +4190,9 @@ static int btusb_probe(struct usb_interface *intf,
} else if (id->driver_info & BTUSB_MEDIATEK) {
/* Allocate extra space for Mediatek device */
priv_size += sizeof(struct btmtk_data);
} else if (id->driver_info & BTUSB_QCA_WCN6855) {
/* Allocate extra space for QCA WCN6855 device */
priv_size += sizeof(struct btqca_data);
}
data->recv_acl = hci_recv_frame;
@@ -4302,8 +4335,10 @@ static int btusb_probe(struct usb_interface *intf,
}
if (id->driver_info & BTUSB_QCA_WCN6855) {
data->qca_dump.id_vendor = id->idVendor;
data->qca_dump.id_product = id->idProduct;
struct btqca_data *btqca_data = hci_get_priv(hdev);
btqca_data->qca_dump.id_vendor = id->idVendor;
btqca_data->qca_dump.id_product = id->idProduct;
data->recv_event = btusb_recv_evt_qca;
data->recv_acl = btusb_recv_acl_qca;
hci_devcd_register(hdev, btusb_coredump_qca, btusb_dump_hdr_qca, NULL);

View File

@@ -247,7 +247,7 @@ static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name)
struct hci_uart *hu = hci_get_drvdata(hdev);
struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);
const struct firmware *firmware = NULL;
struct aml_fw_len *fw_len = NULL;
const struct aml_fw_len *fw_len = NULL;
u8 *iccm_start = NULL, *dccm_start = NULL;
u32 iccm_len, dccm_len;
u32 value = 0;
@@ -281,7 +281,21 @@ static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name)
goto exit;
}
fw_len = (struct aml_fw_len *)firmware->data;
if (firmware->size < sizeof(*fw_len)) {
bt_dev_err(hdev, "Firmware is too small for its header");
ret = -EINVAL;
goto exit;
}
fw_len = (const struct aml_fw_len *)firmware->data;
if (fw_len->iccm_len < amldev->aml_dev_data->iccm_offset ||
fw_len->iccm_len > firmware->size - sizeof(*fw_len) ||
fw_len->dccm_len > firmware->size - sizeof(*fw_len) -
fw_len->iccm_len) {
bt_dev_err(hdev, "Invalid firmware segment lengths");
ret = -EINVAL;
goto exit;
}
/* Download ICCM */
iccm_start = (u8 *)(firmware->data) + sizeof(struct aml_fw_len)

View File

@@ -1314,174 +1314,174 @@ static struct bcm_device_data bcm43430_device_data = {
};
static const struct acpi_device_id bcm_acpi_match[] = {
{ "BCM2E00" },
{ "BCM2E01" },
{ "BCM2E02" },
{ "BCM2E03" },
{ "BCM2E04" },
{ "BCM2E05" },
{ "BCM2E06" },
{ "BCM2E07" },
{ "BCM2E08" },
{ "BCM2E09" },
{ "BCM2E0A" },
{ "BCM2E0B" },
{ "BCM2E0C" },
{ "BCM2E0D" },
{ "BCM2E0E" },
{ "BCM2E0F" },
{ "BCM2E10" },
{ "BCM2E11" },
{ "BCM2E12" },
{ "BCM2E13" },
{ "BCM2E14" },
{ "BCM2E15" },
{ "BCM2E16" },
{ "BCM2E17" },
{ "BCM2E18" },
{ "BCM2E19" },
{ "BCM2E1A" },
{ "BCM2E1B" },
{ "BCM2E1C" },
{ "BCM2E1D" },
{ "BCM2E1F" },
{ "BCM2E20" },
{ "BCM2E21" },
{ "BCM2E22" },
{ "BCM2E23" },
{ "BCM2E24" },
{ "BCM2E25" },
{ "BCM2E26" },
{ "BCM2E27" },
{ "BCM2E28" },
{ "BCM2E29" },
{ "BCM2E2A" },
{ "BCM2E2B" },
{ "BCM2E2C" },
{ "BCM2E2D" },
{ "BCM2E2E" },
{ "BCM2E2F" },
{ "BCM2E30" },
{ "BCM2E31" },
{ "BCM2E32" },
{ "BCM2E33" },
{ "BCM2E34" },
{ "BCM2E35" },
{ "BCM2E36" },
{ "BCM2E37" },
{ "BCM2E38" },
{ "BCM2E39" },
{ "BCM2E3A" },
{ "BCM2E3B" },
{ "BCM2E3C" },
{ "BCM2E3D" },
{ "BCM2E3E" },
{ "BCM2E3F" },
{ "BCM2E40" },
{ "BCM2E41" },
{ "BCM2E42" },
{ "BCM2E43" },
{ "BCM2E44" },
{ "BCM2E45" },
{ "BCM2E46" },
{ "BCM2E47" },
{ "BCM2E48" },
{ "BCM2E49" },
{ "BCM2E4A" },
{ "BCM2E4B" },
{ "BCM2E4C" },
{ "BCM2E4D" },
{ "BCM2E4E" },
{ "BCM2E4F" },
{ "BCM2E50" },
{ "BCM2E51" },
{ "BCM2E52" },
{ "BCM2E53" },
{ "BCM2E54" },
{ "BCM2E55" },
{ "BCM2E56" },
{ "BCM2E57" },
{ "BCM2E58" },
{ "BCM2E59" },
{ "BCM2E5A" },
{ "BCM2E5B" },
{ "BCM2E5C" },
{ "BCM2E5D" },
{ "BCM2E5E" },
{ "BCM2E5F" },
{ "BCM2E60" },
{ "BCM2E61" },
{ "BCM2E62" },
{ "BCM2E63" },
{ "BCM2E64" },
{ "BCM2E65" },
{ "BCM2E66" },
{ "BCM2E67" },
{ "BCM2E68" },
{ "BCM2E69" },
{ "BCM2E6B" },
{ "BCM2E6D" },
{ "BCM2E6E" },
{ "BCM2E6F" },
{ "BCM2E70" },
{ "BCM2E71" },
{ "BCM2E72" },
{ "BCM2E73" },
{ "BCM2E74", (long)&bcm43430_device_data },
{ "BCM2E75", (long)&bcm43430_device_data },
{ "BCM2E76" },
{ "BCM2E77" },
{ "BCM2E78" },
{ "BCM2E79" },
{ "BCM2E7A" },
{ "BCM2E7B", (long)&bcm43430_device_data },
{ "BCM2E7C" },
{ "BCM2E7D" },
{ "BCM2E7E" },
{ "BCM2E7F" },
{ "BCM2E80", (long)&bcm43430_device_data },
{ "BCM2E81" },
{ "BCM2E82" },
{ "BCM2E83" },
{ "BCM2E84" },
{ "BCM2E85" },
{ "BCM2E86" },
{ "BCM2E87" },
{ "BCM2E88" },
{ "BCM2E89", (long)&bcm43430_device_data },
{ "BCM2E8A" },
{ "BCM2E8B" },
{ "BCM2E8C" },
{ "BCM2E8D" },
{ "BCM2E8E" },
{ "BCM2E90" },
{ "BCM2E92" },
{ "BCM2E93" },
{ "BCM2E94", (long)&bcm43430_device_data },
{ "BCM2E95" },
{ "BCM2E96" },
{ "BCM2E97" },
{ "BCM2E98" },
{ "BCM2E99", (long)&bcm43430_device_data },
{ "BCM2E9A" },
{ "BCM2E9B", (long)&bcm43430_device_data },
{ "BCM2E9C" },
{ "BCM2E9D" },
{ "BCM2E9F", (long)&bcm43430_device_data },
{ "BCM2EA0" },
{ "BCM2EA1" },
{ "BCM2EA2", (long)&bcm43430_device_data },
{ "BCM2EA3", (long)&bcm43430_device_data },
{ "BCM2EA4", (long)&bcm43430_device_data }, /* bcm43455 */
{ "BCM2EA5" },
{ "BCM2EA6" },
{ "BCM2EA7" },
{ "BCM2EA8" },
{ "BCM2EA9" },
{ "BCM2EAA", (long)&bcm43430_device_data },
{ "BCM2EAB", (long)&bcm43430_device_data },
{ "BCM2EAC", (long)&bcm43430_device_data },
{ },
{ .id = "BCM2E00" },
{ .id = "BCM2E01" },
{ .id = "BCM2E02" },
{ .id = "BCM2E03" },
{ .id = "BCM2E04" },
{ .id = "BCM2E05" },
{ .id = "BCM2E06" },
{ .id = "BCM2E07" },
{ .id = "BCM2E08" },
{ .id = "BCM2E09" },
{ .id = "BCM2E0A" },
{ .id = "BCM2E0B" },
{ .id = "BCM2E0C" },
{ .id = "BCM2E0D" },
{ .id = "BCM2E0E" },
{ .id = "BCM2E0F" },
{ .id = "BCM2E10" },
{ .id = "BCM2E11" },
{ .id = "BCM2E12" },
{ .id = "BCM2E13" },
{ .id = "BCM2E14" },
{ .id = "BCM2E15" },
{ .id = "BCM2E16" },
{ .id = "BCM2E17" },
{ .id = "BCM2E18" },
{ .id = "BCM2E19" },
{ .id = "BCM2E1A" },
{ .id = "BCM2E1B" },
{ .id = "BCM2E1C" },
{ .id = "BCM2E1D" },
{ .id = "BCM2E1F" },
{ .id = "BCM2E20" },
{ .id = "BCM2E21" },
{ .id = "BCM2E22" },
{ .id = "BCM2E23" },
{ .id = "BCM2E24" },
{ .id = "BCM2E25" },
{ .id = "BCM2E26" },
{ .id = "BCM2E27" },
{ .id = "BCM2E28" },
{ .id = "BCM2E29" },
{ .id = "BCM2E2A" },
{ .id = "BCM2E2B" },
{ .id = "BCM2E2C" },
{ .id = "BCM2E2D" },
{ .id = "BCM2E2E" },
{ .id = "BCM2E2F" },
{ .id = "BCM2E30" },
{ .id = "BCM2E31" },
{ .id = "BCM2E32" },
{ .id = "BCM2E33" },
{ .id = "BCM2E34" },
{ .id = "BCM2E35" },
{ .id = "BCM2E36" },
{ .id = "BCM2E37" },
{ .id = "BCM2E38" },
{ .id = "BCM2E39" },
{ .id = "BCM2E3A" },
{ .id = "BCM2E3B" },
{ .id = "BCM2E3C" },
{ .id = "BCM2E3D" },
{ .id = "BCM2E3E" },
{ .id = "BCM2E3F" },
{ .id = "BCM2E40" },
{ .id = "BCM2E41" },
{ .id = "BCM2E42" },
{ .id = "BCM2E43" },
{ .id = "BCM2E44" },
{ .id = "BCM2E45" },
{ .id = "BCM2E46" },
{ .id = "BCM2E47" },
{ .id = "BCM2E48" },
{ .id = "BCM2E49" },
{ .id = "BCM2E4A" },
{ .id = "BCM2E4B" },
{ .id = "BCM2E4C" },
{ .id = "BCM2E4D" },
{ .id = "BCM2E4E" },
{ .id = "BCM2E4F" },
{ .id = "BCM2E50" },
{ .id = "BCM2E51" },
{ .id = "BCM2E52" },
{ .id = "BCM2E53" },
{ .id = "BCM2E54" },
{ .id = "BCM2E55" },
{ .id = "BCM2E56" },
{ .id = "BCM2E57" },
{ .id = "BCM2E58" },
{ .id = "BCM2E59" },
{ .id = "BCM2E5A" },
{ .id = "BCM2E5B" },
{ .id = "BCM2E5C" },
{ .id = "BCM2E5D" },
{ .id = "BCM2E5E" },
{ .id = "BCM2E5F" },
{ .id = "BCM2E60" },
{ .id = "BCM2E61" },
{ .id = "BCM2E62" },
{ .id = "BCM2E63" },
{ .id = "BCM2E64" },
{ .id = "BCM2E65" },
{ .id = "BCM2E66" },
{ .id = "BCM2E67" },
{ .id = "BCM2E68" },
{ .id = "BCM2E69" },
{ .id = "BCM2E6B" },
{ .id = "BCM2E6D" },
{ .id = "BCM2E6E" },
{ .id = "BCM2E6F" },
{ .id = "BCM2E70" },
{ .id = "BCM2E71" },
{ .id = "BCM2E72" },
{ .id = "BCM2E73" },
{ .id = "BCM2E74", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2E75", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2E76" },
{ .id = "BCM2E77" },
{ .id = "BCM2E78" },
{ .id = "BCM2E79" },
{ .id = "BCM2E7A" },
{ .id = "BCM2E7B", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2E7C" },
{ .id = "BCM2E7D" },
{ .id = "BCM2E7E" },
{ .id = "BCM2E7F" },
{ .id = "BCM2E80", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2E81" },
{ .id = "BCM2E82" },
{ .id = "BCM2E83" },
{ .id = "BCM2E84" },
{ .id = "BCM2E85" },
{ .id = "BCM2E86" },
{ .id = "BCM2E87" },
{ .id = "BCM2E88" },
{ .id = "BCM2E89", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2E8A" },
{ .id = "BCM2E8B" },
{ .id = "BCM2E8C" },
{ .id = "BCM2E8D" },
{ .id = "BCM2E8E" },
{ .id = "BCM2E90" },
{ .id = "BCM2E92" },
{ .id = "BCM2E93" },
{ .id = "BCM2E94", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2E95" },
{ .id = "BCM2E96" },
{ .id = "BCM2E97" },
{ .id = "BCM2E98" },
{ .id = "BCM2E99", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2E9A" },
{ .id = "BCM2E9B", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2E9C" },
{ .id = "BCM2E9D" },
{ .id = "BCM2E9F", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2EA0" },
{ .id = "BCM2EA1" },
{ .id = "BCM2EA2", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2EA3", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2EA4", .driver_data = (long)&bcm43430_device_data }, /* bcm43455 */
{ .id = "BCM2EA5" },
{ .id = "BCM2EA6" },
{ .id = "BCM2EA7" },
{ .id = "BCM2EA8" },
{ .id = "BCM2EA9" },
{ .id = "BCM2EAA", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2EAB", .driver_data = (long)&bcm43430_device_data },
{ .id = "BCM2EAC", .driver_data = (long)&bcm43430_device_data },
{ }
};
MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
#endif

View File

@@ -194,7 +194,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
return NULL;
}
if (hciextn && chan == 5) {
if (hciextn && chan == 5 && len > HCI_COMMAND_HDR_SIZE) {
__le16 opcode = ((struct hci_command_hdr *)data)->opcode;
/* Vendor specific commands */
@@ -402,6 +402,9 @@ static void bcsp_handle_le_pkt(struct hci_uart *hu)
u8 sync_pkt[4] = { 0xda, 0xdc, 0xed, 0xed };
/* spot "conf" pkts and reply with a "conf rsp" pkt */
if (bcsp->rx_skb->len < 8)
return;
if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
!memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) {
struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);

View File

@@ -1124,10 +1124,10 @@ static const struct h5_device_data h5_data_rtl8723bs = {
#ifdef CONFIG_ACPI
static const struct acpi_device_id h5_acpi_match[] = {
#ifdef CONFIG_BT_HCIUART_RTL
{ "OBDA0623", (kernel_ulong_t)&h5_data_rtl8723bs },
{ "OBDA8723", (kernel_ulong_t)&h5_data_rtl8723bs },
{ .id = "OBDA0623", .driver_data = (kernel_ulong_t)&h5_data_rtl8723bs },
{ .id = "OBDA8723", .driver_data = (kernel_ulong_t)&h5_data_rtl8723bs },
#endif
{ },
{ }
};
MODULE_DEVICE_TABLE(acpi, h5_acpi_match);
#endif

View File

@@ -1057,8 +1057,8 @@ static const struct hci_uart_proto intel_proto = {
#ifdef CONFIG_ACPI
static const struct acpi_device_id intel_acpi_match[] = {
{ "INT33E1", 0 },
{ "INT33E3", 0 },
{ .id = "INT33E1" },
{ .id = "INT33E3" },
{ }
};
MODULE_DEVICE_TABLE(acpi, intel_acpi_match);

View File

@@ -163,6 +163,12 @@ static void hci_uart_write_work(struct work_struct *work)
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
len = tty->ops->write(tty, skb->data, skb->len);
if (len < 0 || len > skb->len) {
hdev->stat.err_tx++;
kfree_skb(skb);
continue;
}
hdev->stat.byte_tx += len;
skb_pull(skb, len);
@@ -756,9 +762,9 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
hu->proto = p;
err = hci_uart_register_dev(hu);
if (err) {
if (err)
return err;
}
set_bit(HCI_UART_PROTO_READY, &hu->flags);
clear_bit(HCI_UART_PROTO_INIT, &hu->flags);

View File

@@ -354,9 +354,29 @@ static int nokia_setup_fw(struct hci_uart *hu)
u16 opcode;
struct sk_buff *skb;
if (pkt_size > fw_size - 2) {
err = -EINVAL;
dev_err(dev, "%s: Malformed firmware packet\n",
hu->hdev->name);
goto done;
}
switch (pkt_type) {
case HCI_COMMAND_PKT:
if (pkt_size < 1 + HCI_COMMAND_HDR_SIZE) {
err = -EINVAL;
dev_err(dev, "%s: Malformed firmware command\n",
hu->hdev->name);
goto done;
}
cmd = (struct hci_command_hdr *)(fw_ptr + 3);
if (cmd->plen > pkt_size - 1 - HCI_COMMAND_HDR_SIZE) {
err = -EINVAL;
dev_err(dev, "%s: Truncated firmware command\n",
hu->hdev->name);
goto done;
}
opcode = le16_to_cpu(cmd->opcode);
skb = __hci_cmd_sync(hu->hdev, opcode, cmd->plen,

View File

@@ -1239,8 +1239,8 @@ static int qca_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
* received we store dump into a file before closing hci. This
* dump will help in triaging the issues.
*/
if ((skb->data[0] == HCI_VENDOR_PKT) &&
(get_unaligned_be16(skb->data + 2) == QCA_SSR_DUMP_HANDLE))
if (skb->data[0] == HCI_EV_VENDOR &&
get_unaligned_be16(skb->data + 2) == QCA_SSR_DUMP_HANDLE)
return qca_controller_memdump_event(hdev, skb);
return hci_recv_frame(hdev, skb);
@@ -2792,12 +2792,12 @@ MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id qca_bluetooth_acpi_match[] = {
{ "QCOM2066", (kernel_ulong_t)&qca_soc_data_qca2066 },
{ "QCOM6390", (kernel_ulong_t)&qca_soc_data_qca6390 },
{ "DLA16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
{ "DLB16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
{ "DLB26390", (kernel_ulong_t)&qca_soc_data_qca6390 },
{ },
{ .id = "QCOM2066", .driver_data = (kernel_ulong_t)&qca_soc_data_qca2066 },
{ .id = "QCOM6390", .driver_data = (kernel_ulong_t)&qca_soc_data_qca6390 },
{ .id = "DLA16390", .driver_data = (kernel_ulong_t)&qca_soc_data_qca6390 },
{ .id = "DLB16390", .driver_data = (kernel_ulong_t)&qca_soc_data_qca6390 },
{ .id = "DLB26390", .driver_data = (kernel_ulong_t)&qca_soc_data_qca6390 },
{ }
};
MODULE_DEVICE_TABLE(acpi, qca_bluetooth_acpi_match);
#endif

View File

@@ -120,9 +120,13 @@ static int virtbt_setup_zephyr(struct hci_dev *hdev)
if (IS_ERR(skb))
return PTR_ERR(skb);
bt_dev_info(hdev, "%s", (char *)(skb->data + 1));
/* Bounded print: the backend controls skb->len. */
if (skb->len > 1) {
int len = skb->len - 1;
hci_set_fw_info(hdev, "%s", skb->data + 1);
bt_dev_info(hdev, "%.*s", len, (char *)(skb->data + 1));
hci_set_fw_info(hdev, "%.*s", len, skb->data + 1);
}
kfree_skb(skb);
return 0;

View File

@@ -8,6 +8,13 @@
#define DEVCOREDUMP_TIMEOUT msecs_to_jiffies(10000) /* 10 sec */
/*
* Max header size, shared by both the devcoredump core and
* the dmp_hdr() registered by driver via hci_devcd_register()
*/
#define HCI_DEVCD_HDR_SIZE_MAX 512
#define HCI_DEVCD_HDR_END_MARKER "--- Start dump ---\n"
typedef void (*coredump_t)(struct hci_dev *hdev);
typedef void (*dmp_hdr_t)(struct hci_dev *hdev, struct sk_buff *skb);
typedef void (*notify_change_t)(struct hci_dev *hdev, int state);
@@ -60,6 +67,8 @@ struct hci_devcoredump {
#ifdef CONFIG_DEV_COREDUMP
const char *hci_devcd_state_name(enum devcoredump_state state);
void hci_devcd_reset(struct hci_dev *hdev);
void hci_devcd_rx(struct work_struct *work);
void hci_devcd_timeout(struct work_struct *work);
@@ -74,6 +83,11 @@ int hci_devcd_abort(struct hci_dev *hdev);
#else
static inline const char *hci_devcd_state_name(enum devcoredump_state state)
{
return "";
}
static inline void hci_devcd_reset(struct hci_dev *hdev) {}
static inline void hci_devcd_rx(struct work_struct *work) {}
static inline void hci_devcd_timeout(struct work_struct *work) {}

View File

@@ -653,6 +653,8 @@ enum {
#define HCI_LE_LL_EXT_FEATURE 0x80
#define HCI_LE_CS 0x40
#define HCI_LE_CS_HOST 0x80
#define HCI_LE_SCI 0x01 /* byte 9 - Shorter Connection Intervals */
#define HCI_LE_SCI_HOST 0x02 /* byte 9 - Shorter Connection Intervals (Host) */
/* Connection modes */
#define HCI_CM_ACTIVE 0x0000
@@ -2489,6 +2491,46 @@ struct hci_cp_le_set_host_feature_v2 {
__u8 bit_value;
} __packed;
#define HCI_OP_LE_CONN_RATE 0x20a1
struct hci_cp_le_conn_rate {
__le16 handle;
__le16 interval_min;
__le16 interval_max;
__le16 subrate_min;
__le16 subrate_max;
__le16 max_latency;
__le16 cont_num;
__le16 supv_timeout;
__le16 min_ce_len;
__le16 max_ce_len;
} __packed;
#define HCI_OP_LE_SET_DEF_RATE 0x20a2
struct hci_cp_le_set_def_rate {
__le16 interval_min;
__le16 interval_max;
__le16 subrate_min;
__le16 subrate_max;
__le16 max_latency;
__le16 cont_num;
__le16 supv_timeout;
__le16 min_ce_len;
__le16 max_ce_len;
} __packed;
#define HCI_OP_LE_READ_CONN_INTERVAL 0x20a3
struct hci_le_conn_interval_group {
__le16 min;
__le16 max;
__le16 stride;
} __packed;
struct hci_rp_le_read_conn_interval {
__u8 status;
__u8 num_grps;
struct hci_le_conn_interval_group grps[];
} __packed;
/* ---- HCI Events ---- */
struct hci_ev_status {
__u8 status;
@@ -3303,6 +3345,17 @@ struct hci_evt_le_cs_test_end_complete {
__u8 status;
} __packed;
#define HCI_EVT_LE_CONN_RATE_CHANGE 0x37
struct hci_evt_le_conn_rate_change {
__u8 status;
__le16 handle;
__le16 interval;
__le16 subrate;
__le16 latency;
__le16 cont_number;
__le16 supv_timeout;
} __packed;
#define HCI_EV_VENDOR 0xff
/* Internal events generated by Bluetooth stack */
@@ -3329,6 +3382,7 @@ struct hci_ev_si_security {
/* ---- HCI Packet structures ---- */
#define HCI_COMMAND_HDR_SIZE 3
#define HCI_EVENT_HDR_SIZE 2
#define HCI_MAX_EVENT_PLEN 255
#define HCI_ACL_HDR_SIZE 4
#define HCI_SCO_HDR_SIZE 3
#define HCI_ISO_HDR_SIZE 4
@@ -3407,6 +3461,16 @@ static inline struct hci_iso_hdr *hci_iso_hdr(const struct sk_buff *skb)
#define hci_handle(h) (h & 0x0fff)
#define hci_flags(h) (h >> 12)
static inline __u16 hci_acl_handle(const struct sk_buff *skb)
{
return hci_handle(__le16_to_cpu(hci_acl_hdr(skb)->handle));
}
static inline __u16 hci_acl_dlen(const struct sk_buff *skb)
{
return __le16_to_cpu(hci_acl_hdr(skb)->dlen);
}
/* ISO handle and flags pack/unpack */
#define hci_iso_flags_pb(f) (f & 0x0003)
#define hci_iso_flags_ts(f) ((f >> 2) & 0x0001)

View File

@@ -416,6 +416,7 @@ struct hci_dev {
__u16 le_conn_max_interval;
__u16 le_conn_latency;
__u16 le_supv_timeout;
__u16 le_min_rate_interval;
__u16 le_def_tx_len;
__u16 le_def_tx_time;
__u16 le_max_tx_len;
@@ -645,6 +646,8 @@ struct hci_dev {
int (*setup)(struct hci_dev *hdev);
int (*shutdown)(struct hci_dev *hdev);
int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
/* Handle HCI_EV_VENDOR; return true if handled, false otherwise */
bool (*handle_ev_vendor)(struct hci_dev *hdev, struct sk_buff *skb);
void (*notify)(struct hci_dev *hdev, unsigned int evt);
void (*hw_error)(struct hci_dev *hdev, u8 code);
int (*post_init)(struct hci_dev *hdev);
@@ -720,6 +723,11 @@ struct hci_conn {
__u16 le_conn_interval;
__u16 le_conn_latency;
__u16 le_supv_timeout;
__u16 le_rate_interval;
__u16 le_subrate;
__u16 le_rate_latency;
__u16 le_cont_num;
__u16 le_rate_supv_timeout;
__u8 le_adv_data[HCI_MAX_EXT_AD_LENGTH];
__u8 le_adv_data_len;
__u8 le_per_adv_data[HCI_MAX_PER_AD_TOT_LEN];
@@ -769,7 +777,7 @@ struct hci_conn {
struct hci_dev *hdev;
spinlock_t proto_lock; /* lock guarding protocol data */
void *l2cap_data;
void *l2cap_data __guarded_by(&proto_lock, &hdev->lock);
void *sco_data;
void *iso_data __guarded_by(&proto_lock);
@@ -812,6 +820,14 @@ struct hci_conn_params {
u16 conn_latency;
u16 supervision_timeout;
u16 rate_min_interval;
u16 rate_max_interval;
u16 subrate_min;
u16 subrate_max;
u16 max_latency;
u16 cont_num;
u16 rate_supv_timeout;
enum {
HCI_AUTO_CONN_DISABLED,
HCI_AUTO_CONN_REPORT,
@@ -1771,7 +1787,13 @@ int hci_register_suspend_notifier(struct hci_dev *hdev);
int hci_unregister_suspend_notifier(struct hci_dev *hdev);
int hci_suspend_dev(struct hci_dev *hdev);
int hci_resume_dev(struct hci_dev *hdev);
int hci_reset_dev(struct hci_dev *hdev);
int __hci_reset_dev(struct hci_dev *hdev, u8 hw_err_code);
static inline int hci_reset_dev(struct hci_dev *hdev)
{
return __hci_reset_dev(hdev, 0);
}
int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb);
__printf(2, 3) void hci_set_hw_info(struct hci_dev *hdev, const char *fmt, ...);
@@ -2079,6 +2101,11 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define le_cs_host_capable(dev) \
((dev)->le_features[5] & HCI_LE_CS_HOST)
#define le_sci_capable(dev) \
((dev)->le_features[9] & HCI_LE_SCI)
#define le_sci_enabled(dev) \
(le_enabled(dev) && le_sci_capable(dev))
#define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \
(!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG)))
@@ -2494,6 +2521,8 @@ void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
bdaddr_t *bdaddr, u8 addr_type);
void mgmt_conn_subrate_notify(struct hci_dev *hdev, struct hci_conn *conn,
u8 status);
int hci_abort_conn(struct hci_conn *conn, u8 reason);
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,

View File

@@ -59,6 +59,7 @@ int __hci_cmd_sync_status(struct hci_dev *hdev, u16 opcode, u32 plen,
int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u8 event, u32 timeout,
struct sock *sk);
int __hci_reset_sync(struct hci_dev *hdev);
int hci_cmd_sync_status(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u32 timeout);
@@ -84,9 +85,6 @@ void hci_cmd_sync_cancel_entry(struct hci_dev *hdev,
struct hci_cmd_sync_work_entry *entry);
bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy);
bool hci_cmd_sync_dequeue_once(struct hci_dev *hdev,
hci_cmd_sync_work_func_t func, void *data,
hci_cmd_sync_work_destroy_t destroy);
int hci_update_eir_sync(struct hci_dev *hdev);
int hci_update_class_sync(struct hci_dev *hdev);
@@ -185,6 +183,7 @@ int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
struct hci_conn_params *params);
int hci_le_conn_rate_request(struct hci_dev *hdev, struct hci_conn *conn);
int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn);

View File

@@ -118,6 +118,7 @@ struct mgmt_rp_read_index_list {
#define MGMT_SETTING_LL_PRIVACY BIT(22)
#define MGMT_SETTING_PAST_SENDER BIT(23)
#define MGMT_SETTING_PAST_RECEIVER BIT(24)
#define MGMT_SETTING_SCI BIT(25)
#define MGMT_OP_READ_INFO 0x0004
#define MGMT_READ_INFO_SIZE 0
@@ -893,6 +894,23 @@ struct mgmt_cp_hci_cmd_sync {
} __packed;
#define MGMT_HCI_CMD_SYNC_SIZE 6
#define MGMT_OP_LOAD_CONN_SUBRATE 0x005C
struct mgmt_conn_subrate {
struct mgmt_addr_info addr;
__le16 min_interval;
__le16 max_interval;
__le16 subrate_min;
__le16 subrate_max;
__le16 max_latency;
__le16 cont_num;
__le16 supv_timeout;
} __packed;
struct mgmt_cp_load_conn_subrate {
__le16 param_count;
struct mgmt_conn_subrate params[] __counted_by_le(param_count);
} __packed;
#define MGMT_LOAD_CONN_SUBRATE_SIZE 2
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
@@ -1192,3 +1210,14 @@ struct mgmt_ev_mesh_device_found {
struct mgmt_ev_mesh_pkt_cmplt {
__u8 handle;
} __packed;
#define MGMT_EV_CONN_SUBRATE 0x0033
struct mgmt_ev_conn_subrate {
struct mgmt_addr_info addr;
__u8 status;
__le16 interval;
__le16 subrate;
__le16 latency;
__le16 cont_num;
__le16 supv_timeout;
} __packed;

View File

@@ -1007,6 +1007,8 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
return -ENOENT;
}
lockdep_assert_held(&hcon->hdev->lock);
*conn = l2cap_conn_hold_unless_zero(hcon->l2cap_data);
BT_DBG("conn %p dst %pMR type %u", *conn, &hcon->dst, hcon->dst_type);

View File

@@ -76,7 +76,7 @@ config BT_LE_L2CAP_ECRED
config BT_6LOWPAN
tristate "Bluetooth 6LoWPAN support"
depends on BT_LE && 6LOWPAN
depends on BT && BT_LE && 6LOWPAN
help
IPv6 compression over Bluetooth Low Energy.

View File

@@ -25,3 +25,5 @@ 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
CONTEXT_ANALYSIS := y

View File

@@ -209,6 +209,7 @@ bool bt_sock_linked(struct bt_sock_list *l, struct sock *s)
EXPORT_SYMBOL(bt_sock_linked);
void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
__context_unsafe(/* conditional locking */)
{
const struct cred *old_cred;
struct pid *old_pid;
@@ -815,7 +816,8 @@ EXPORT_SYMBOL(bt_sock_wait_ready);
#ifdef CONFIG_PROC_FS
static void *bt_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(seq->private->l->lock)
__acquires_shared(&((struct bt_sock_list *)
pde_data(file_inode(seq->file)))->lock)
{
struct bt_sock_list *l = pde_data(file_inode(seq->file));
@@ -831,7 +833,8 @@ static void *bt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}
static void bt_seq_stop(struct seq_file *seq, void *v)
__releases(seq->private->l->lock)
__releases_shared(&((struct bt_sock_list *)
pde_data(file_inode(seq->file)))->lock)
{
struct bt_sock_list *l = pde_data(file_inode(seq->file));

View File

@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config BT_BNEP
tristate "BNEP protocol support"
depends on BT_BREDR
depends on BT && BT_BREDR
select CRC32
help
BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet

View File

@@ -6,3 +6,5 @@
obj-$(CONFIG_BT_BNEP) += bnep.o
bnep-objs := core.o sock.o netdev.o
CONTEXT_ANALYSIS := y

View File

@@ -30,10 +30,9 @@ struct hci_devcoredump_skb_pattern {
#define DBG_UNEXPECTED_STATE() \
bt_dev_dbg(hdev, \
"Unexpected packet (%d) for state (%d). ", \
hci_dmp_cb(skb)->pkt_type, hdev->dump.state)
#define MAX_DEVCOREDUMP_HDR_SIZE 512 /* bytes */
"Unexpected packet (%d) for state %s.", \
hci_dmp_cb(skb)->pkt_type, \
hci_devcd_state_name(hdev->dump.state))
static int hci_devcd_update_hdr_state(char *buf, size_t size, int state)
{
@@ -50,8 +49,9 @@ static int hci_devcd_update_hdr_state(char *buf, size_t size, int state)
/* Call with hci_dev_lock only. */
static int hci_devcd_update_state(struct hci_dev *hdev, int state)
{
bt_dev_dbg(hdev, "Updating devcoredump state from %d to %d.",
hdev->dump.state, state);
bt_dev_dbg(hdev, "Updating devcoredump state from %s to %s.",
hci_devcd_state_name(hdev->dump.state),
hci_devcd_state_name(state));
hdev->dump.state = state;
@@ -61,7 +61,6 @@ static int hci_devcd_update_state(struct hci_dev *hdev, int state)
static int hci_devcd_mkheader(struct hci_dev *hdev, struct sk_buff *skb)
{
char dump_start[] = "--- Start dump ---\n";
char hdr[80];
int hdr_len;
@@ -72,7 +71,7 @@ static int hci_devcd_mkheader(struct hci_dev *hdev, struct sk_buff *skb)
if (hdev->dump.dmp_hdr)
hdev->dump.dmp_hdr(hdev, skb);
skb_put_data(skb, dump_start, strlen(dump_start));
skb_put_data(skb, HCI_DEVCD_HDR_END_MARKER, strlen(HCI_DEVCD_HDR_END_MARKER));
return skb->len;
}
@@ -152,7 +151,7 @@ static int hci_devcd_prepare(struct hci_dev *hdev, u32 dump_size)
int dump_hdr_size;
int err = 0;
skb = alloc_skb(MAX_DEVCOREDUMP_HDR_SIZE, GFP_ATOMIC);
skb = alloc_skb(HCI_DEVCD_HDR_SIZE_MAX, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
@@ -245,7 +244,7 @@ static void hci_devcd_dump(struct hci_dev *hdev)
struct sk_buff *skb;
u32 size;
bt_dev_dbg(hdev, "state %d", hdev->dump.state);
bt_dev_dbg(hdev, "state %s", hci_devcd_state_name(hdev->dump.state));
size = hdev->dump.tail - hdev->dump.head;
@@ -368,8 +367,9 @@ void hci_devcd_rx(struct work_struct *work)
break;
default:
bt_dev_dbg(hdev, "Unknown packet (%d) for state (%d). ",
hci_dmp_cb(skb)->pkt_type, hdev->dump.state);
bt_dev_dbg(hdev, "Unknown packet (%d) for state %s.",
hci_dmp_cb(skb)->pkt_type,
hci_devcd_state_name(hdev->dump.state));
break;
}
@@ -390,7 +390,6 @@ void hci_devcd_rx(struct work_struct *work)
hci_dev_unlock(hdev);
}
}
EXPORT_SYMBOL(hci_devcd_rx);
void hci_devcd_timeout(struct work_struct *work)
{
@@ -416,7 +415,6 @@ void hci_devcd_timeout(struct work_struct *work)
hci_dev_unlock(hdev);
}
EXPORT_SYMBOL(hci_devcd_timeout);
int hci_devcd_register(struct hci_dev *hdev, coredump_t coredump,
dmp_hdr_t dmp_hdr, notify_change_t notify_change)
@@ -551,3 +549,31 @@ int hci_devcd_abort(struct hci_dev *hdev)
return 0;
}
EXPORT_SYMBOL(hci_devcd_abort);
const char *hci_devcd_state_name(enum devcoredump_state state)
{
const char *state_name = "Unknown";
switch (state) {
case HCI_DEVCOREDUMP_IDLE:
state_name = "IDLE";
break;
case HCI_DEVCOREDUMP_ACTIVE:
state_name = "ACTIVE";
break;
case HCI_DEVCOREDUMP_DONE:
state_name = "DONE";
break;
case HCI_DEVCOREDUMP_ABORT:
state_name = "ABORT";
break;
case HCI_DEVCOREDUMP_TIMEOUT:
state_name = "TIMEOUT";
break;
default:
break;
}
return state_name;
}
EXPORT_SYMBOL(hci_devcd_state_name);

View File

@@ -283,8 +283,6 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
struct hci_cp_enhanced_setup_sync_conn cp;
const struct sco_param *param;
kfree(conn_handle);
if (!hci_conn_valid(hdev, conn))
return -ECANCELED;
@@ -453,6 +451,15 @@ static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
return true;
}
static void hci_enhanced_setup_sync_destroy(struct hci_dev *hdev, void *data,
int err)
{
struct conn_handle_t *conn_handle = data;
hci_conn_put(conn_handle->conn);
kfree(conn_handle);
}
bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
{
int result;
@@ -464,12 +471,15 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
if (!conn_handle)
return false;
conn_handle->conn = conn;
conn_handle->conn = hci_conn_get(conn);
conn_handle->handle = handle;
result = hci_cmd_sync_queue(conn->hdev, hci_enhanced_setup_sync,
conn_handle, NULL);
if (result < 0)
conn_handle,
hci_enhanced_setup_sync_destroy);
if (result < 0) {
hci_conn_put(conn);
kfree(conn_handle);
}
return result == 0;
}

View File

@@ -62,6 +62,7 @@ static DEFINE_IDA(hci_index_ida);
/* Get HCI device by index.
* Device is held on return. */
static struct hci_dev *__hci_dev_get(int index, int *srcu_index)
__context_unsafe(/* conditional locking */)
{
struct hci_dev *hdev = NULL, *d;
@@ -89,11 +90,13 @@ struct hci_dev *hci_dev_get(int index)
}
static struct hci_dev *hci_dev_get_srcu(int index, int *srcu_index)
__context_unsafe(/* conditional locking vs return */)
{
return __hci_dev_get(index, srcu_index);
}
static void hci_dev_put_srcu(struct hci_dev *hdev, int srcu_index)
__context_unsafe(/* conditional locking vs return */)
{
srcu_read_unlock(&hdev->srcu, srcu_index);
hci_dev_put(hdev);
@@ -2849,9 +2852,9 @@ int hci_resume_dev(struct hci_dev *hdev)
EXPORT_SYMBOL(hci_resume_dev);
/* Reset HCI device */
int hci_reset_dev(struct hci_dev *hdev)
int __hci_reset_dev(struct hci_dev *hdev, u8 hw_err_code)
{
static const u8 hw_err[] = { HCI_EV_HARDWARE_ERROR, 0x01, 0x00 };
const u8 hw_err[] = { HCI_EV_HARDWARE_ERROR, 0x01, hw_err_code };
struct sk_buff *skb;
skb = bt_skb_alloc(3, GFP_ATOMIC);
@@ -2866,7 +2869,7 @@ int hci_reset_dev(struct hci_dev *hdev)
/* Send Hardware Error to upper stack */
return hci_recv_frame(hdev, skb);
}
EXPORT_SYMBOL(hci_reset_dev);
EXPORT_SYMBOL(__hci_reset_dev);
static u8 hci_dev_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb)
{
@@ -2901,10 +2904,9 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
if (hci_conn_num(hdev, CIS_LINK) ||
hci_conn_num(hdev, BIS_LINK) ||
hci_conn_num(hdev, PA_LINK)) {
__u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
__u8 type;
type = hci_conn_lookup_type(hdev, hci_handle(handle));
type = hci_conn_lookup_type(hdev, hci_acl_handle(skb));
if (type == CIS_LINK || type == BIS_LINK ||
type == PA_LINK)
hci_skb_pkt_type(skb) = HCI_ISODATA_PKT;

View File

@@ -1161,16 +1161,12 @@ static ssize_t force_no_mitm_write(struct file *file,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
char buf[32];
size_t buf_size = min(count, (sizeof(buf) - 1));
bool enable;
int err;
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
buf[buf_size] = '\0';
if (kstrtobool(buf, &enable))
return -EINVAL;
err = kstrtobool_from_user(user_buf, count, &enable);
if (err)
return err;
if (enable == hci_dev_test_flag(hdev, HCI_FORCE_NO_MITM))
return -EALREADY;

View File

@@ -269,7 +269,10 @@ static u8 hci_cc_reset(struct hci_dev *hdev, void *data, struct sk_buff *skb)
{
struct hci_ev_status *rp = data;
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
if (rp->status)
bt_dev_err(hdev, "status 0x%2.2x", rp->status);
else
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
clear_bit(HCI_RESET, &hdev->flags);
@@ -294,8 +297,10 @@ static u8 hci_cc_reset(struct hci_dev *hdev, void *data, struct sk_buff *skb)
hdev->ssp_debug_mode = 0;
hci_dev_lock(hdev);
hci_bdaddr_list_clear(&hdev->le_accept_list);
hci_bdaddr_list_clear(&hdev->le_resolv_list);
hci_dev_unlock(hdev);
return rp->status;
}
@@ -1238,6 +1243,39 @@ static u8 hci_cc_le_read_local_features(struct hci_dev *hdev, void *data,
return rp->status;
}
static u8 hci_cc_le_read_conn_interval(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_rp_le_read_conn_interval *rp = data;
u16 min_interval = 0;
int i;
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
if (rp->status)
return rp->status;
if (skb->len < flex_array_size(rp, grps, rp->num_grps)) {
bt_dev_err(hdev, "Invalid response length for 0x%4.4x",
HCI_OP_LE_READ_CONN_INTERVAL);
return HCI_ERROR_UNSPECIFIED;
}
/* Store the smallest minimum supported connection interval reported by
* the controller so the default rate parameters can be clamped to it.
*/
for (i = 0; i < rp->num_grps; i++) {
u16 min = le16_to_cpu(rp->grps[i].min);
if (!min_interval || min < min_interval)
min_interval = min;
}
hdev->le_min_rate_interval = min_interval;
return rp->status;
}
static u8 hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
@@ -3827,8 +3865,10 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_CIG_PARAMS);
if (!rp->status && (!cp || rp->num_handles != cp->num_cis ||
rp->cig_id != cp->cig_id)) {
if (!rp->status &&
(!cp || rp->num_handles != cp->num_cis ||
rp->cig_id != cp->cig_id ||
skb->len < array_size(rp->num_handles, sizeof(*rp->handle)))) {
bt_dev_err(hdev, "unexpected Set CIG Parameters response data");
status = HCI_ERROR_UNSPECIFIED;
}
@@ -4150,6 +4190,9 @@ static const struct hci_cc {
sizeof(struct hci_rp_le_read_buffer_size)),
HCI_CC(HCI_OP_LE_READ_LOCAL_FEATURES, hci_cc_le_read_local_features,
sizeof(struct hci_rp_le_read_local_features)),
HCI_CC_VL(HCI_OP_LE_READ_CONN_INTERVAL, hci_cc_le_read_conn_interval,
sizeof(struct hci_rp_le_read_conn_interval),
HCI_MAX_EVENT_SIZE),
HCI_CC(HCI_OP_LE_READ_ADV_TX_POWER, hci_cc_le_read_adv_tx_power,
sizeof(struct hci_rp_le_read_adv_tx_power)),
HCI_CC(HCI_OP_USER_CONFIRM_REPLY, hci_cc_user_confirm_reply,
@@ -5864,6 +5907,17 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
}
}
/* If we are central and have subrate parameters stored, queue a
* connection rate request to apply them.
*/
if (conn->role == HCI_ROLE_MASTER && le_sci_capable(hdev)) {
struct hci_conn_params *p;
p = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
if (p && p->subrate_max)
hci_le_conn_rate_request(hdev, conn);
}
unlock:
hci_update_passive_scan(hdev);
hci_dev_unlock(hdev);
@@ -6604,6 +6658,13 @@ static void hci_le_per_adv_report_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "sync_handle 0x%4.4x", le16_to_cpu(ev->sync_handle));
/* The reassembly in iso_connect_ind() copies ev->length bytes from the
* stored event, so make sure the event actually carries that many data
* bytes before it is consumed.
*/
if (!hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_PER_ADV_REPORT, ev->length))
return;
hci_dev_lock(hdev);
mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, PA_LINK, &flags);
@@ -7360,6 +7421,36 @@ static void hci_le_read_all_remote_features_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev);
}
static void hci_le_conn_rate_change_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_evt_le_conn_rate_change *ev = data;
struct hci_conn *conn;
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
/* Only update the stored rate parameters on success; on
* failure the values in the event are not valid. Userspace is
* notified either way.
*/
if (!ev->status) {
conn->le_rate_interval = le16_to_cpu(ev->interval);
conn->le_subrate = le16_to_cpu(ev->subrate);
conn->le_rate_latency = le16_to_cpu(ev->latency);
conn->le_cont_num = le16_to_cpu(ev->cont_number);
conn->le_rate_supv_timeout =
le16_to_cpu(ev->supv_timeout);
}
mgmt_conn_subrate_notify(hdev, conn, ev->status);
}
hci_dev_unlock(hdev);
}
#define HCI_LE_EV_VL(_op, _func, _min_len, _max_len) \
[_op] = { \
.func = _func, \
@@ -7471,6 +7562,9 @@ static const struct hci_le_ev {
sizeof(struct
hci_evt_le_read_all_remote_features_complete),
HCI_MAX_EVENT_SIZE),
/* [0x37 = HCI_EVT_LE_CONN_RATE_CHANGE] */
HCI_LE_EV(HCI_EVT_LE_CONN_RATE_CHANGE, hci_le_conn_rate_change_evt,
sizeof(struct hci_evt_le_conn_rate_change)),
};
static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
@@ -7517,6 +7611,14 @@ static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
subev->func(hdev, data, skb);
}
static void hci_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
{
if (hdev->handle_ev_vendor && hdev->handle_ev_vendor(hdev, skb))
return;
msft_vendor_evt(hdev, data, skb);
}
static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
u8 event, struct sk_buff *skb)
{
@@ -7633,7 +7735,7 @@ static const struct hci_ev {
HCI_EV_STATUS(HCI_EV_INQUIRY_COMPLETE, hci_inquiry_complete_evt),
/* [0x02 = HCI_EV_INQUIRY_RESULT] */
HCI_EV_VL(HCI_EV_INQUIRY_RESULT, hci_inquiry_result_evt,
sizeof(struct hci_ev_inquiry_result), HCI_MAX_EVENT_SIZE),
sizeof(struct hci_ev_inquiry_result), HCI_MAX_EVENT_PLEN),
/* [0x03 = HCI_EV_CONN_COMPLETE] */
HCI_EV(HCI_EV_CONN_COMPLETE, hci_conn_complete_evt,
sizeof(struct hci_ev_conn_complete)),
@@ -7661,7 +7763,7 @@ static const struct hci_ev {
sizeof(struct hci_ev_remote_features)),
/* [0x0e = HCI_EV_CMD_COMPLETE] */
HCI_EV_REQ_VL(HCI_EV_CMD_COMPLETE, hci_cmd_complete_evt,
sizeof(struct hci_ev_cmd_complete), HCI_MAX_EVENT_SIZE),
sizeof(struct hci_ev_cmd_complete), HCI_MAX_EVENT_PLEN),
/* [0x0f = HCI_EV_CMD_STATUS] */
HCI_EV_REQ(HCI_EV_CMD_STATUS, hci_cmd_status_evt,
sizeof(struct hci_ev_cmd_status)),
@@ -7673,7 +7775,7 @@ static const struct hci_ev {
sizeof(struct hci_ev_role_change)),
/* [0x13 = HCI_EV_NUM_COMP_PKTS] */
HCI_EV_VL(HCI_EV_NUM_COMP_PKTS, hci_num_comp_pkts_evt,
sizeof(struct hci_ev_num_comp_pkts), HCI_MAX_EVENT_SIZE),
sizeof(struct hci_ev_num_comp_pkts), HCI_MAX_EVENT_PLEN),
/* [0x14 = HCI_EV_MODE_CHANGE] */
HCI_EV(HCI_EV_MODE_CHANGE, hci_mode_change_evt,
sizeof(struct hci_ev_mode_change)),
@@ -7699,7 +7801,7 @@ static const struct hci_ev {
HCI_EV_VL(HCI_EV_INQUIRY_RESULT_WITH_RSSI,
hci_inquiry_result_with_rssi_evt,
sizeof(struct hci_ev_inquiry_result_rssi),
HCI_MAX_EVENT_SIZE),
HCI_MAX_EVENT_PLEN),
/* [0x23 = HCI_EV_REMOTE_EXT_FEATURES] */
HCI_EV(HCI_EV_REMOTE_EXT_FEATURES, hci_remote_ext_features_evt,
sizeof(struct hci_ev_remote_ext_features)),
@@ -7709,7 +7811,7 @@ static const struct hci_ev {
/* [0x2f = HCI_EV_EXTENDED_INQUIRY_RESULT] */
HCI_EV_VL(HCI_EV_EXTENDED_INQUIRY_RESULT,
hci_extended_inquiry_result_evt,
sizeof(struct hci_ev_ext_inquiry_result), HCI_MAX_EVENT_SIZE),
sizeof(struct hci_ev_ext_inquiry_result), HCI_MAX_EVENT_PLEN),
/* [0x30 = HCI_EV_KEY_REFRESH_COMPLETE] */
HCI_EV(HCI_EV_KEY_REFRESH_COMPLETE, hci_key_refresh_complete_evt,
sizeof(struct hci_ev_key_refresh_complete)),
@@ -7742,9 +7844,9 @@ static const struct hci_ev {
sizeof(struct hci_ev_remote_host_features)),
/* [0x3e = HCI_EV_LE_META] */
HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt,
sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE),
sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_PLEN),
/* [0xff = HCI_EV_VENDOR] */
HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE),
HCI_EV_VL(HCI_EV_VENDOR, hci_vendor_evt, 0, HCI_MAX_EVENT_PLEN),
};
static void hci_event_func(struct hci_dev *hdev, u8 event, struct sk_buff *skb,

View File

@@ -540,8 +540,6 @@ static int adv_timeout_expire_sync(struct hci_dev *hdev, void *data)
{
u8 instance = *(u8 *)data;
kfree(data);
hci_clear_adv_instance_sync(hdev, NULL, instance, false);
if (list_empty(&hdev->adv_instances))
@@ -550,6 +548,12 @@ static int adv_timeout_expire_sync(struct hci_dev *hdev, void *data)
return 0;
}
static void adv_timeout_expire_destroy(struct hci_dev *hdev, void *data,
int err)
{
kfree(data);
}
static void adv_timeout_expire(struct work_struct *work)
{
u8 *inst_ptr;
@@ -570,7 +574,9 @@ static void adv_timeout_expire(struct work_struct *work)
goto unlock;
*inst_ptr = hdev->cur_adv_instance;
hci_cmd_sync_queue(hdev, adv_timeout_expire_sync, inst_ptr, NULL);
if (hci_cmd_sync_queue(hdev, adv_timeout_expire_sync, inst_ptr,
adv_timeout_expire_destroy) < 0)
kfree(inst_ptr);
unlock:
hci_dev_unlock(hdev);
@@ -860,32 +866,6 @@ void hci_cmd_sync_cancel_entry(struct hci_dev *hdev,
}
EXPORT_SYMBOL(hci_cmd_sync_cancel_entry);
/* Dequeue one HCI command entry:
*
* - Lookup and cancel first entry that matches.
*/
bool hci_cmd_sync_dequeue_once(struct hci_dev *hdev,
hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy)
{
struct hci_cmd_sync_work_entry *entry;
mutex_lock(&hdev->cmd_sync_work_lock);
entry = _hci_cmd_sync_lookup_entry(hdev, func, data, destroy);
if (!entry) {
mutex_unlock(&hdev->cmd_sync_work_lock);
return false;
}
_hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
mutex_unlock(&hdev->cmd_sync_work_lock);
return true;
}
EXPORT_SYMBOL(hci_cmd_sync_dequeue_once);
/* Dequeue HCI command entry:
*
* - Lookup and cancel any entry that matches by function callback or data or
@@ -1170,6 +1150,32 @@ int hci_update_random_address_sync(struct hci_dev *hdev, bool require_privacy,
return 0;
}
static int hci_disable_ext_adv_legacy_instance_sync(struct hci_dev *hdev)
{
struct hci_cp_le_set_ext_adv_enable *cp;
struct hci_cp_ext_adv_set *set;
u8 data[sizeof(*cp) + sizeof(*set) * 1];
u8 size;
if (!hci_dev_test_flag(hdev, HCI_LE_ADV_0))
return 0;
memset(data, 0, sizeof(data));
cp = (void *)data;
set = (void *)cp->data;
cp->num_of_sets = 0x01;
cp->enable = 0x00;
set->handle = 0x00;
size = sizeof(*cp) + sizeof(*set) * cp->num_of_sets;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_ENABLE,
size, data, HCI_CMD_TIMEOUT);
}
static int hci_disable_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
{
struct hci_cp_le_set_ext_adv_enable *cp;
@@ -1395,6 +1401,10 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
return -EINVAL;
}
} else {
err = hci_disable_ext_adv_legacy_instance_sync(hdev);
if (err)
return err;
adv = NULL;
}
@@ -3780,18 +3790,20 @@ static const struct hci_init_stage hci_init0[] = {
int hci_reset_sync(struct hci_dev *hdev)
{
int err;
set_bit(HCI_RESET, &hdev->flags);
err = __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL,
HCI_CMD_TIMEOUT);
if (err)
return err;
return 0;
return __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL,
HCI_CMD_TIMEOUT);
}
/* Send a raw HCI reset for use by vendor drivers */
int __hci_reset_sync(struct hci_dev *hdev)
{
return __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL,
HCI_INIT_TIMEOUT);
}
EXPORT_SYMBOL(__hci_reset_sync);
static int hci_init0_sync(struct hci_dev *hdev)
{
int err;
@@ -4565,6 +4577,10 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
events[6] |= 0x02; /* LE CS Subevent Result Continue event */
events[6] |= 0x04; /* LE CS Test End Complete event */
}
if (le_sci_capable(hdev))
events[6] |= 0x40; /* LE Connection Rate Change event */
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EVENT_MASK,
sizeof(events), events, HCI_CMD_TIMEOUT);
}
@@ -4733,12 +4749,59 @@ static int hci_le_set_host_feature_sync(struct hci_dev *hdev, u16 bit, u8 value)
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
static int hci_le_read_conn_interval_sync(struct hci_dev *hdev)
{
if (!le_sci_capable(hdev))
return 0;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_CONN_INTERVAL,
0, NULL, HCI_CMD_TIMEOUT);
}
static int hci_le_set_def_rate_sync(struct hci_dev *hdev)
{
struct hci_cp_le_set_def_rate cp;
u16 interval_min = 0x000a; /* 1.25 ms */
u16 interval_max = 0x0078; /* 15 ms */
if (!le_sci_capable(hdev))
return 0;
/* Clamp the interval range to the controller's minimum supported
* connection interval (read via HCI_OP_LE_READ_CONN_INTERVAL) so the
* default rate parameters are not rejected. The maximum is raised as
* well if needed to keep interval_min <= interval_max.
*/
if (hdev->le_min_rate_interval > interval_min) {
interval_min = hdev->le_min_rate_interval;
if (interval_min > interval_max)
interval_max = interval_min;
}
memset(&cp, 0, sizeof(cp));
/* Use the HIDS 1.2 recommended Full Range mode values as the default
* rate parameters (see HOGP v1.2 spec). Connection intervals are in
* units of 0.125 ms and the supervision timeout is in units of 10 ms.
*/
cp.interval_min = cpu_to_le16(interval_min);
cp.interval_max = cpu_to_le16(interval_max);
cp.subrate_min = cpu_to_le16(0x0001);
cp.subrate_max = cpu_to_le16(0x0004);
cp.max_latency = cpu_to_le16(0x0000);
cp.cont_num = cpu_to_le16(0x0001);
cp.supv_timeout = cpu_to_le16(0x000c); /* 120 ms */
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_DEF_RATE,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
/* Set Host Features, each feature needs to be sent separately since
* HCI_OP_LE_SET_HOST_FEATURE doesn't support setting all of them at once.
*/
static int hci_le_set_host_features_sync(struct hci_dev *hdev)
{
int err;
int err = 0;
if (cis_capable(hdev)) {
/* Connected Isochronous Channels (Host Support) */
@@ -4749,9 +4812,16 @@ static int hci_le_set_host_features_sync(struct hci_dev *hdev)
return err;
}
if (le_cs_capable(hdev))
if (le_cs_capable(hdev)) {
/* Channel Sounding (Host Support) */
err = hci_le_set_host_feature_sync(hdev, 47, 0x01);
if (err)
return err;
}
if (le_sci_capable(hdev))
/* Shorter Connection Intervals (Host Support) */
err = hci_le_set_host_feature_sync(hdev, 73, 0x01);
return err;
}
@@ -4784,6 +4854,10 @@ static const struct hci_init_stage le_init3[] = {
HCI_INIT(hci_set_le_support_sync),
/* HCI_OP_LE_SET_HOST_FEATURE */
HCI_INIT(hci_le_set_host_features_sync),
/* HCI_OP_LE_READ_CONN_INTERVAL */
HCI_INIT(hci_le_read_conn_interval_sync),
/* HCI_OP_LE_SET_DEF_RATE */
HCI_INIT(hci_le_set_def_rate_sync),
{}
};
@@ -6313,6 +6387,8 @@ static int hci_pause_discovery_sync(struct hci_dev *hdev)
static int hci_update_event_filter_sync(struct hci_dev *hdev)
{
struct bdaddr_list_with_flags *b;
bdaddr_t *accept_list;
size_t i, num_entries = 0;
u8 scan = SCAN_DISABLED;
bool scanning = test_bit(HCI_PSCAN, &hdev->flags);
int err;
@@ -6329,23 +6405,49 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev)
/* Always clear event filter when starting */
hci_clear_event_filter_sync(hdev);
list_for_each_entry(b, &hdev->accept_list, list) {
if (!(b->flags & HCI_CONN_FLAG_REMOTE_WAKEUP))
continue;
hci_dev_lock(hdev);
bt_dev_dbg(hdev, "Adding event filters for %pMR", &b->bdaddr);
list_for_each_entry(b, &hdev->accept_list, list)
if (b->flags & HCI_CONN_FLAG_REMOTE_WAKEUP)
num_entries++;
err = hci_set_event_filter_sync(hdev, HCI_FLT_CONN_SETUP,
HCI_CONN_SETUP_ALLOW_BDADDR,
&b->bdaddr,
HCI_CONN_SETUP_AUTO_ON);
if (!num_entries) {
hci_dev_unlock(hdev);
goto update_scan;
}
accept_list = kmalloc_array(num_entries, sizeof(*accept_list),
GFP_KERNEL);
if (!accept_list) {
hci_dev_unlock(hdev);
return -ENOMEM;
}
i = 0;
list_for_each_entry(b, &hdev->accept_list, list)
if (b->flags & HCI_CONN_FLAG_REMOTE_WAKEUP)
bacpy(&accept_list[i++], &b->bdaddr);
hci_dev_unlock(hdev);
for (i = 0; i < num_entries; i++) {
bt_dev_dbg(hdev, "Adding event filters for %pMR",
&accept_list[i]);
err = hci_set_event_filter_sync(hdev, HCI_FLT_CONN_SETUP,
HCI_CONN_SETUP_ALLOW_BDADDR,
&accept_list[i],
HCI_CONN_SETUP_AUTO_ON);
if (err)
bt_dev_err(hdev, "Failed to set event filter for %pMR",
&b->bdaddr);
&accept_list[i]);
else
scan = SCAN_PAGE;
}
kfree(accept_list);
update_scan:
if (scan && !scanning)
hci_write_scan_enable_sync(hdev, scan);
else if (!scan && scanning)
@@ -7317,6 +7419,75 @@ int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
static int hci_le_conn_rate_request_sync(struct hci_dev *hdev, void *data)
{
struct hci_conn *conn = data;
struct hci_conn_params *params;
struct hci_cp_le_conn_rate cp;
hci_dev_lock(hdev);
/* The request was queued asynchronously so re-validate the connection
* and its parameters under hdev->lock. The connection may have been
* torn down, or may not have a valid handle yet (still connecting),
* and the parameters may have been removed in the meantime (e.g. by
* Load Connection Parameters). Snapshot the rate values so the
* blocking command below can run without holding hdev->lock.
*/
if (!hci_conn_valid(hdev, conn) ||
HCI_CONN_HANDLE_UNSET(conn->handle)) {
hci_dev_unlock(hdev);
return -ECANCELED;
}
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
if (!params) {
hci_dev_unlock(hdev);
return -ECANCELED;
}
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(conn->handle);
cp.interval_min = cpu_to_le16(params->rate_min_interval);
cp.interval_max = cpu_to_le16(params->rate_max_interval);
cp.subrate_min = cpu_to_le16(params->subrate_min);
cp.subrate_max = cpu_to_le16(params->subrate_max);
cp.max_latency = cpu_to_le16(params->max_latency);
cp.cont_num = cpu_to_le16(params->cont_num);
cp.supv_timeout = cpu_to_le16(params->rate_supv_timeout);
cp.min_ce_len = cpu_to_le16(0x0000);
cp.max_ce_len = cpu_to_le16(0x0000);
hci_dev_unlock(hdev);
return __hci_cmd_sync_status(hdev, HCI_OP_LE_CONN_RATE,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
static void hci_le_conn_rate_request_destroy(struct hci_dev *hdev, void *data,
int err)
{
struct hci_conn *conn = data;
hci_conn_put(conn);
}
int hci_le_conn_rate_request(struct hci_dev *hdev, struct hci_conn *conn)
{
int err;
/* Hold a reference to the connection so it cannot be freed while the
* request is pending or running on the cmd_sync worker.
*/
err = hci_cmd_sync_queue(hdev, hci_le_conn_rate_request_sync,
hci_conn_get(conn),
hci_le_conn_rate_request_destroy);
if (err < 0)
hci_conn_put(conn);
return err;
}
static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
{
struct hci_conn *conn = data;

View File

@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config BT_HIDP
tristate "HIDP protocol support"
depends on BT_BREDR && HID
depends on BT && BT_BREDR && HID
help
HIDP (Human Interface Device Protocol) is a transport layer
for HID reports. HIDP is required for the Bluetooth Human

View File

@@ -6,3 +6,5 @@
obj-$(CONFIG_BT_HIDP) += hidp.o
hidp-objs := core.o sock.o
CONTEXT_ANALYSIS := y

View File

@@ -1536,6 +1536,7 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr,
lock_sock(sk);
memset(sa, 0, sizeof(struct sockaddr_iso));
addr->sa_family = AF_BLUETOOTH;
if (peer) {
@@ -1546,6 +1547,7 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr,
sa->iso_bdaddr_type = iso_pi(sk)->dst_type;
if (hcon && (hcon->type == BIS_LINK || hcon->type == PA_LINK)) {
memset(sa->iso_bc, 0, sizeof(struct sockaddr_iso_bc));
sa->iso_bc->bc_sid = iso_pi(sk)->bc_sid;
sa->iso_bc->bc_num_bis = iso_pi(sk)->bc_num_bis;
memcpy(sa->iso_bc->bc_bis, iso_pi(sk)->bc_bis,
@@ -1658,9 +1660,9 @@ static void iso_conn_defer_accept(struct hci_conn *conn)
hci_send_cmd(hdev, HCI_OP_LE_ACCEPT_CIS, sizeof(cp), &cp);
}
static void iso_conn_big_sync(struct sock *sk)
static int iso_conn_big_sync(struct sock *sk)
{
int err;
int err = 0;
struct hci_dev *hdev;
struct iso_conn *conn;
bdaddr_t src, dst;
@@ -1675,7 +1677,7 @@ static void iso_conn_big_sync(struct sock *sk)
hdev = hci_get_route(&dst, &src, src_type);
if (!hdev)
return;
return -EHOSTUNREACH;
/* hci_le_big_create_sync requires hdev lock to be held, since
* it enqueues the HCI LE BIG Create Sync command via
@@ -1691,8 +1693,10 @@ static void iso_conn_big_sync(struct sock *sk)
* both before dereferencing conn->hcon.
*/
conn = iso_pi(sk)->conn;
if (!conn || !conn->hcon)
if (!conn || !conn->hcon) {
err = -ENOTCONN;
goto unlock;
}
if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
err = hci_conn_big_create_sync(hdev, conn->hcon,
@@ -1708,6 +1712,8 @@ static void iso_conn_big_sync(struct sock *sk)
release_sock(sk);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;
}
static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -1732,10 +1738,19 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
case BT_CONNECT2:
if (test_bit(BT_SK_PA_SYNC, &pi->flags)) {
release_sock(sk);
iso_conn_big_sync(sk);
err = iso_conn_big_sync(sk);
lock_sock(sk);
sk->sk_state = BT_LISTEN;
/* The socket lock was dropped, so the
* connection may have been torn down
* meanwhile and iso_chan_del() may have
* already moved the socket to BT_CLOSED.
* Only move on to BT_LISTEN if the BIG sync
* was actually started and nothing else has
* changed the state.
*/
if (!err && sk->sk_state == BT_CONNECT2)
sk->sk_state = BT_LISTEN;
} else {
iso_conn_defer_accept(pi->conn->hcon);
sk->sk_state = BT_CONFIG;
@@ -1746,10 +1761,11 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
case BT_CONNECTED:
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
release_sock(sk);
iso_conn_big_sync(sk);
err = iso_conn_big_sync(sk);
lock_sock(sk);
sk->sk_state = BT_LISTEN;
if (!err && sk->sk_state == BT_CONNECTED)
sk->sk_state = BT_LISTEN;
early_ret = true;
}

View File

@@ -1791,6 +1791,7 @@ static void l2cap_unregister_all_users(struct l2cap_conn *conn)
}
static void l2cap_conn_del(struct hci_conn *hcon, int err)
__must_hold(&hcon->hdev->lock)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_chan *chan, *l;
@@ -1833,7 +1834,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
hci_chan_del(conn->hchan);
conn->hchan = NULL;
spin_lock(&hcon->proto_lock);
hcon->l2cap_data = NULL;
spin_unlock(&hcon->proto_lock);
mutex_unlock(&conn->lock);
l2cap_conn_put(conn);
}
@@ -7150,6 +7154,7 @@ static void process_pending_rx(struct work_struct *work)
}
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
__must_hold(&hcon->hdev->lock)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct hci_chan *hchan;
@@ -7168,8 +7173,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
}
kref_init(&conn->ref);
hcon->l2cap_data = conn;
conn->hcon = hci_conn_get(hcon);
conn->hchan = hchan;
BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
@@ -7198,6 +7201,11 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
spin_lock(&hcon->proto_lock);
conn->hcon = hci_conn_get(hcon);
hcon->l2cap_data = conn;
spin_unlock(&hcon->proto_lock);
return conn;
}
@@ -7352,6 +7360,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
goto done;
}
lockdep_assert_held(&hcon->hdev->lock);
conn = l2cap_conn_add(hcon);
if (!conn) {
hci_conn_drop(hcon);
@@ -7522,6 +7532,7 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
}
static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
__must_hold(&hcon->hdev->lock)
{
struct hci_dev *hdev = hcon->hdev;
struct l2cap_conn *conn;
@@ -7582,16 +7593,22 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
int l2cap_disconn_ind(struct hci_conn *hcon)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_conn *conn;
int ret = HCI_ERROR_REMOTE_USER_TERM;
BT_DBG("hcon %p", hcon);
if (!conn)
return HCI_ERROR_REMOTE_USER_TERM;
return conn->disc_reason;
spin_lock(&hcon->proto_lock);
conn = hcon->l2cap_data;
if (conn)
ret = conn->disc_reason;
spin_unlock(&hcon->proto_lock);
return ret;
}
static void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
__must_hold(&hcon->hdev->lock)
{
if (hcon->type != ACL_LINK && hcon->type != LE_LINK)
return;
@@ -7619,6 +7636,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
}
static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
__must_hold(&hcon->hdev->lock)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_chan *chan;
@@ -7803,6 +7821,8 @@ int l2cap_recv_acldata(struct hci_dev *hdev, u16 handle,
return -ENOENT;
}
lockdep_assert_held(&hcon->hdev->lock);
hci_conn_enter_active_mode(hcon, BT_POWER_FORCE_ACTIVE_OFF);
conn = hcon->l2cap_data;

View File

@@ -1365,6 +1365,7 @@ static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan)
}
static int l2cap_sock_shutdown(struct socket *sock, int how)
__context_unsafe(/* complex chan->conn locking */)
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan;

View File

@@ -861,6 +861,9 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (past_receiver_capable(hdev))
settings |= MGMT_SETTING_PAST_RECEIVER;
if (le_sci_capable(hdev))
settings |= MGMT_SETTING_SCI;
settings |= MGMT_SETTING_PHY_CONFIGURATION;
return settings;
@@ -952,6 +955,9 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (past_receiver_enabled(hdev))
settings |= MGMT_SETTING_PAST_RECEIVER;
if (le_sci_enabled(hdev))
settings |= MGMT_SETTING_SCI;
return settings;
}
@@ -2431,11 +2437,15 @@ static int send_cancel(struct hci_dev *hdev, void *data)
mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
0, NULL, 0);
mgmt_pending_free(cmd);
return 0;
}
static void send_cancel_destroy(struct hci_dev *hdev, void *data, int err)
{
mgmt_pending_free(data);
}
static int mesh_send_cancel(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
@@ -2456,7 +2466,8 @@ static int mesh_send_cancel(struct sock *sk, struct hci_dev *hdev,
if (!cmd)
err = -ENOMEM;
else
err = hci_cmd_sync_queue(hdev, send_cancel, cmd, NULL);
err = hci_cmd_sync_queue(hdev, send_cancel, cmd,
send_cancel_destroy);
if (err < 0) {
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
@@ -2642,7 +2653,7 @@ static int send_hci_cmd_sync(struct hci_dev *hdev, void *data)
if (IS_ERR(skb)) {
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC,
mgmt_status(PTR_ERR(skb)));
goto done;
return 0;
}
mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
@@ -2650,12 +2661,14 @@ static int send_hci_cmd_sync(struct hci_dev *hdev, void *data)
kfree_skb(skb);
done:
mgmt_pending_free(cmd);
return 0;
}
static void send_hci_cmd_sync_destroy(struct hci_dev *hdev, void *data, int err)
{
mgmt_pending_free(data);
}
static int mgmt_hci_cmd_sync(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
@@ -2668,12 +2681,21 @@ static int mgmt_hci_cmd_sync(struct sock *sk, struct hci_dev *hdev,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_HCI_CMD_SYNC,
MGMT_STATUS_INVALID_PARAMS);
/* The HCI command header carries the parameter length in a u8, a
* larger value would be truncated there while the parameters are
* still appended to the frame in full.
*/
if (le16_to_cpu(cp->params_len) > U8_MAX)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_HCI_CMD_SYNC,
MGMT_STATUS_INVALID_PARAMS);
hci_dev_lock(hdev);
cmd = mgmt_pending_new(sk, MGMT_OP_HCI_CMD_SYNC, hdev, data, len);
if (!cmd)
err = -ENOMEM;
else
err = hci_cmd_sync_queue(hdev, send_hci_cmd_sync, cmd, NULL);
err = hci_cmd_sync_queue(hdev, send_hci_cmd_sync, cmd,
send_hci_cmd_sync_destroy);
if (err < 0) {
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_HCI_CMD_SYNC,
@@ -3870,6 +3892,8 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
}
if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
lockdep_assert_held(&conn->hdev->lock);
err = smp_user_confirm_reply(conn, mgmt_op, passkey);
if (!err)
err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
@@ -8170,6 +8194,118 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
NULL, 0);
}
static int load_conn_subrate(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
struct mgmt_cp_load_conn_subrate *cp = data;
const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
sizeof(struct mgmt_conn_subrate));
u16 param_count, expected_len;
int i;
if (!lmp_le_capable(hdev) || !le_sci_capable(hdev))
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_SUBRATE,
MGMT_STATUS_NOT_SUPPORTED);
param_count = __le16_to_cpu(cp->param_count);
if (param_count > max_param_count) {
bt_dev_err(hdev, "too big param_count value %u", param_count);
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_SUBRATE,
MGMT_STATUS_INVALID_PARAMS);
}
expected_len = struct_size(cp, params, param_count);
if (expected_len != len) {
bt_dev_err(hdev, "expected %u bytes, got %u bytes",
expected_len, len);
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_SUBRATE,
MGMT_STATUS_INVALID_PARAMS);
}
bt_dev_dbg(hdev, "param_count %u", param_count);
hci_dev_lock(hdev);
for (i = 0; i < param_count; i++) {
struct mgmt_conn_subrate *param = &cp->params[i];
struct hci_conn_params *hci_param;
u16 min, max, subrate_min, subrate_max;
u16 max_latency, cont_num, supv_timeout;
u8 addr_type;
bt_dev_dbg(hdev, "Adding subrate %pMR (type %u)",
&param->addr.bdaddr, param->addr.type);
if (param->addr.type == BDADDR_LE_PUBLIC) {
addr_type = ADDR_LE_DEV_PUBLIC;
} else if (param->addr.type == BDADDR_LE_RANDOM) {
addr_type = ADDR_LE_DEV_RANDOM;
} else {
bt_dev_err(hdev, "ignoring invalid connection subrate parameters");
continue;
}
min = le16_to_cpu(param->min_interval);
max = le16_to_cpu(param->max_interval);
subrate_min = le16_to_cpu(param->subrate_min);
subrate_max = le16_to_cpu(param->subrate_max);
max_latency = le16_to_cpu(param->max_latency);
cont_num = le16_to_cpu(param->cont_num);
supv_timeout = le16_to_cpu(param->supv_timeout);
/* Validate the parameters before storing them. Reject
* logically inconsistent values instead of forwarding them to
* the controller.
*/
if (min > max || subrate_min > subrate_max ||
subrate_min < 1 || supv_timeout < 1) {
bt_dev_err(hdev, "ignoring invalid connection subrate parameters");
continue;
}
hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
addr_type);
if (!hci_param) {
bt_dev_err(hdev, "failed to add connection parameters");
continue;
}
hci_param->rate_min_interval = min;
hci_param->rate_max_interval = max;
hci_param->subrate_min = subrate_min;
hci_param->subrate_max = subrate_max;
hci_param->max_latency = max_latency;
hci_param->cont_num = cont_num;
hci_param->rate_supv_timeout = supv_timeout;
/* If the device is connected as central check if the
* connection rate parameters need to be updated.
*/
if (!i && param_count == 1) {
struct hci_conn *conn;
conn = hci_conn_hash_lookup_le(hdev,
&hci_param->addr,
addr_type);
if (conn && conn->state == BT_CONNECTED &&
conn->role == HCI_ROLE_MASTER &&
(conn->le_rate_interval < min ||
conn->le_rate_interval > max ||
conn->le_subrate < subrate_min ||
conn->le_subrate > subrate_max ||
conn->le_rate_latency != max_latency ||
conn->le_cont_num != cont_num ||
conn->le_rate_supv_timeout != supv_timeout))
hci_le_conn_rate_request(hdev, conn);
}
}
hci_dev_unlock(hdev);
return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_SUBRATE, 0,
NULL, 0);
}
static int set_external_config(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
@@ -9587,6 +9723,8 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
HCI_MGMT_VAR_LEN },
{ mesh_send_cancel, MGMT_MESH_SEND_CANCEL_SIZE },
{ mgmt_hci_cmd_sync, MGMT_HCI_CMD_SYNC_SIZE, HCI_MGMT_VAR_LEN },
{ load_conn_subrate, MGMT_LOAD_CONN_SUBRATE_SIZE,
HCI_MGMT_VAR_LEN },
};
void mgmt_index_added(struct hci_dev *hdev)
@@ -10735,6 +10873,23 @@ int mgmt_init(void)
return hci_mgmt_chan_register(&chan);
}
void mgmt_conn_subrate_notify(struct hci_dev *hdev, struct hci_conn *conn,
u8 status)
{
struct mgmt_ev_conn_subrate ev;
bacpy(&ev.addr.bdaddr, &conn->dst);
ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
ev.status = mgmt_status(status);
ev.interval = cpu_to_le16(conn->le_rate_interval);
ev.subrate = cpu_to_le16(conn->le_subrate);
ev.latency = cpu_to_le16(conn->le_rate_latency);
ev.cont_num = cpu_to_le16(conn->le_cont_num);
ev.supv_timeout = cpu_to_le16(conn->le_rate_supv_timeout);
mgmt_event(MGMT_EV_CONN_SUBRATE, hdev, &ev, sizeof(ev), NULL);
}
void mgmt_exit(void)
{
hci_mgmt_chan_unregister(&chan);

View File

@@ -165,6 +165,11 @@ static bool read_supported_features(struct hci_dev *hdev,
if (rp->sub_opcode != MSFT_OP_READ_SUPPORTED_FEATURES)
goto failed;
if (skb->len < sizeof(*rp) + rp->evt_prefix_len) {
bt_dev_err(hdev, "MSFT event prefix length mismatch");
goto failed;
}
if (rp->evt_prefix_len > 0) {
msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len,
GFP_KERNEL);

View File

@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config BT_RFCOMM
tristate "RFCOMM protocol support"
depends on BT_BREDR
depends on BT && BT_BREDR
help
RFCOMM provides connection oriented stream transport. RFCOMM
support is required for Dialup Networking, OBEX and other Bluetooth

View File

@@ -7,3 +7,5 @@ obj-$(CONFIG_BT_RFCOMM) += rfcomm.o
rfcomm-y := core.o sock.o
rfcomm-$(CONFIG_BT_RFCOMM_TTY) += tty.o
CONTEXT_ANALYSIS := y

View File

@@ -1331,7 +1331,10 @@ static struct rfcomm_session *rfcomm_recv_disc(struct rfcomm_session *s,
return s;
}
void rfcomm_dlc_accept(struct rfcomm_dlc *d)
/* Must be called with rfcomm_mutex held, so that the session cannot be
* unlinked from under us.
*/
static void __rfcomm_dlc_accept(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
@@ -1353,6 +1356,21 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d)
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
}
void rfcomm_dlc_accept(struct rfcomm_dlc *d)
{
rfcomm_lock();
/* rfcomm_recv_disc() sets the dlc state to BT_CLOSED before calling
* __rfcomm_dlc_close(), so the RFCOMM_DEFER_SETUP handshake there is
* skipped and the session can already be unlinked by the time the
* deferred accept runs from rfcomm_sock_recvmsg().
*/
if (d->session)
__rfcomm_dlc_accept(d);
rfcomm_unlock();
}
static void rfcomm_check_accept(struct rfcomm_dlc *d)
{
if (rfcomm_check_security(d)) {
@@ -1365,7 +1383,7 @@ static void rfcomm_check_accept(struct rfcomm_dlc *d)
d->state_change(d, 0);
rfcomm_dlc_unlock(d);
} else
rfcomm_dlc_accept(d);
__rfcomm_dlc_accept(d);
} else {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
@@ -1958,7 +1976,7 @@ static void rfcomm_process_dlcs(struct rfcomm_session *s)
d->state_change(d, 0);
rfcomm_dlc_unlock(d);
} else
rfcomm_dlc_accept(d);
__rfcomm_dlc_accept(d);
}
continue;
} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {

View File

@@ -60,6 +60,7 @@ static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
}
static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
__must_hold(&d->lock)
{
struct sock *sk = d->owner, *parent;

View File

@@ -2327,12 +2327,15 @@ static void smp_send_security_req(struct smp_chan *smp, __u8 auth)
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_conn *conn;
struct l2cap_chan *chan;
struct smp_chan *smp;
__u8 authreq;
int ret;
/* Caller shall ensure there can be no race with l2cap_conn_del() */
conn = context_unsafe(hcon->l2cap_data);
bt_dev_dbg(hcon->hdev, "conn %p hcon %p level 0x%2.2x", conn, hcon,
sec_level);
@@ -2421,6 +2424,8 @@ int smp_cancel_and_remove_pairing(struct hci_dev *hdev, bdaddr_t *bdaddr,
if (!hcon)
goto done;
lockdep_assert_held(&hcon->hdev->lock);
conn = hcon->l2cap_data;
if (!conn)
goto done;

View File

@@ -180,11 +180,13 @@ enum smp_key_pref {
/* SMP Commands */
int smp_cancel_and_remove_pairing(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 addr_type);
u8 addr_type)
__must_hold(&hdev->lock);
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,
enum smp_key_pref key_pref);
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey)
__must_hold(&conn->hdev->lock);
bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16],
const bdaddr_t *bdaddr);