diff --git a/Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie b/Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie new file mode 100644 index 000000000000..cceec6ac96bc --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-pci-drivers-btintel_pcie @@ -0,0 +1,15 @@ +What: /sys/bus/pci/devices//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. diff --git a/MAINTAINERS b/MAINTAINERS index 08e43bc09735..891c064a881b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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/ diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index bafc26250b63..e6b1c1180d1d 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -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 diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 8df310983bf6..d31d797639b5 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -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; diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index bf567b7c5f00..bcb2514b7bc0 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -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); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 37d93abdd5a3..966ec1b02be2 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -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) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 2b7231be5973..005c77a4f5eb 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -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 diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index 7caee093e316..749369b24031 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -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; diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index d6f0ad0b4b6e..e25930351f64 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -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", diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 93932a0d8625..b91fc63bc9fe 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -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; diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index c6f80c419e90..4e1012e90979 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -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); diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 6a1cffe08d5f..81cdd8da5636 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include #include @@ -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); } diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 10c496eaea2c..22b08ab05b82 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -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); diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c index 59ad0b9b14c3..3f802b7c83f7 100644 --- a/drivers/bluetooth/btrsi.c +++ b/drivers/bluetooth/btrsi.c @@ -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; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 184e95c1625e..be82bbbc1b5c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -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); diff --git a/drivers/bluetooth/hci_aml.c b/drivers/bluetooth/hci_aml.c index 959d9e67b669..067fbf278b44 100644 --- a/drivers/bluetooth/hci_aml.c +++ b/drivers/bluetooth/hci_aml.c @@ -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) diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 1a4fc3882fd2..01da3fecb536 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -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 diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index db56eead27ce..0323db21c428 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -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); diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 93cdde981840..60b90f1e11fc 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -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 diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index c31105b91e47..ecf597f3e201 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -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); diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 2ad42c3bbaac..58f5504a336e 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -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); diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c index 1e65b541f8ad..be2923231e71 100644 --- a/drivers/bluetooth/hci_nokia.c +++ b/drivers/bluetooth/hci_nokia.c @@ -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, diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 1222f97800f4..345f602e9ce2 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -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 diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c index 140ab55c9fc5..c20d54088c8c 100644 --- a/drivers/bluetooth/virtio_bt.c +++ b/drivers/bluetooth/virtio_bt.c @@ -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; diff --git a/include/net/bluetooth/coredump.h b/include/net/bluetooth/coredump.h index 72f51b587a04..1f071ab55416 100644 --- a/include/net/bluetooth/coredump.h +++ b/include/net/bluetooth/coredump.h @@ -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) {} diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 50f0eef71fb1..1641d879dbda 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -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) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3df59849dcbe..e07418a5adce 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -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, diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h index 73e494b2591d..a6579a868678 100644 --- a/include/net/bluetooth/hci_sync.h +++ b/include/net/bluetooth/hci_sync.h @@ -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); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 08daed7a96d5..1e22eab1081c 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -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; diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index d504a363a30f..30f4afa18bc8 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -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); diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index d250e94e90eb..1cda01614efe 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -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. diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 41049b280887..ff466ea97436 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -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 diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index a2290ffdc2c1..411d66f24393 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -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)); diff --git a/net/bluetooth/bnep/Kconfig b/net/bluetooth/bnep/Kconfig index aac02b5b0d17..f8087e2d2c00 100644 --- a/net/bluetooth/bnep/Kconfig +++ b/net/bluetooth/bnep/Kconfig @@ -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 diff --git a/net/bluetooth/bnep/Makefile b/net/bluetooth/bnep/Makefile index 8af9d56bb012..f42015cc3245 100644 --- a/net/bluetooth/bnep/Makefile +++ b/net/bluetooth/bnep/Makefile @@ -6,3 +6,5 @@ obj-$(CONFIG_BT_BNEP) += bnep.o bnep-objs := core.o sock.o netdev.o + +CONTEXT_ANALYSIS := y diff --git a/net/bluetooth/coredump.c b/net/bluetooth/coredump.c index 720cb79adf96..5bee863bd6d2 100644 --- a/net/bluetooth/coredump.c +++ b/net/bluetooth/coredump.c @@ -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); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b1f911fd4ad6..19b7629b1cc1 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -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; } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5ba9fe8261ec..509c820a693d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -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; diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c index 0635e4641db4..aadffaaff20e 100644 --- a/net/bluetooth/hci_debugfs.c +++ b/net/bluetooth/hci_debugfs.c @@ -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; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 741d658e9630..3eb1eaf6e6a0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -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, diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index c8d14128c363..b5897545d795 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -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; diff --git a/net/bluetooth/hidp/Kconfig b/net/bluetooth/hidp/Kconfig index e08aae35351a..ba52c7296f18 100644 --- a/net/bluetooth/hidp/Kconfig +++ b/net/bluetooth/hidp/Kconfig @@ -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 diff --git a/net/bluetooth/hidp/Makefile b/net/bluetooth/hidp/Makefile index f41b0aa02b23..53e139e41bdc 100644 --- a/net/bluetooth/hidp/Makefile +++ b/net/bluetooth/hidp/Makefile @@ -6,3 +6,5 @@ obj-$(CONFIG_BT_HIDP) += hidp.o hidp-objs := core.o sock.o + +CONTEXT_ANALYSIS := y diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index a461c8a4efed..aa2ce78f56a2 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -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; } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 1156aba4e83c..ee459dd411f5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -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; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 4058ff50cc27..735167f73f31 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -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; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 167d75e34526..860c086011b7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -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)", + ¶m->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, ¶m->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); diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index d7badce8746c..ded68568e6c9 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -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); diff --git a/net/bluetooth/rfcomm/Kconfig b/net/bluetooth/rfcomm/Kconfig index 9b9953ebf4c0..e7af2d565cea 100644 --- a/net/bluetooth/rfcomm/Kconfig +++ b/net/bluetooth/rfcomm/Kconfig @@ -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 diff --git a/net/bluetooth/rfcomm/Makefile b/net/bluetooth/rfcomm/Makefile index 593e5c48c131..15f909f40f25 100644 --- a/net/bluetooth/rfcomm/Makefile +++ b/net/bluetooth/rfcomm/Makefile @@ -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 diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 2e8c080b4d9e..9cdfea666a2c 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -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)) { diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index feb302a491fa..958081adb9b5 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -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; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index c4470958b0d5..f23b695c487b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -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; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index eac27bd541bb..c86c46389007 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -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);