diff --git a/MAINTAINERS b/MAINTAINERS index 2ba1e447f720..7b5a3caebf68 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20686,6 +20686,13 @@ S: Maintained F: Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml F: drivers/net/wwan/qcom_bam_dmux.c +QUALCOMM BLUETOOTH DRIVER +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: drivers/bluetooth/btqca.[ch] +F: drivers/bluetooth/btqcomsmd.c +F: drivers/bluetooth/hci_qca.c + QUALCOMM CAMERA SUBSYSTEM DRIVER M: Robert Foss M: Todor Tomov diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 8b43dfc755de..b7ba667a3d09 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -20,7 +20,7 @@ #include #include -#include "h4_recv.h" +#include "hci_uart.h" #define VERSION "0.11" diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index be69d21c9aa7..9d29ab811f80 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -484,6 +484,7 @@ int btintel_version_info_tlv(struct hci_dev *hdev, case 0x1d: /* BlazarU (BzrU) */ case 0x1e: /* BlazarI (Bzr) */ case 0x1f: /* Scorpious Peak */ + case 0x22: /* BlazarIW (BzrIW) */ break; default: bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)", @@ -3253,6 +3254,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) case 0x1d: case 0x1e: case 0x1f: + case 0x22: hci_set_msft_opcode(hdev, 0xFC1E); break; default: @@ -3593,6 +3595,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) case 0x1d: case 0x1e: case 0x1f: + case 0x22: /* Display version information of TLV type */ btintel_version_info_tlv(hdev, &ver_tlv); diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 6e7bbbd35279..6d3963bd56a9 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -35,8 +36,13 @@ /* Intel Bluetooth PCIe device id table */ static const struct pci_device_id btintel_pcie_table[] = { + /* BlazarI, Wildcat Lake */ { BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) }, + /* BlazarI, Lunar Lake */ { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) }, + /* Scorpious, Panther Lake-H484 */ + { BTINTEL_PCI_DEVICE(0xE376, PCI_ANY_ID) }, + /* Scorpious, Panther Lake-H404 */ { BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) }, { 0 } }; @@ -554,25 +560,6 @@ static void btintel_pcie_mac_init(struct btintel_pcie_data *data) btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); } -static int btintel_pcie_add_dmp_data(struct hci_dev *hdev, const void *data, int size) -{ - struct sk_buff *skb; - int err; - - skb = alloc_skb(size, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - skb_put_data(skb, data, size); - err = hci_devcd_append(hdev, skb); - if (err) { - bt_dev_err(hdev, "Failed to append data in the coredump"); - return err; - } - - return 0; -} - static int btintel_pcie_get_mac_access(struct btintel_pcie_data *data) { u32 reg; @@ -617,30 +604,35 @@ static void btintel_pcie_release_mac_access(struct btintel_pcie_data *data) btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); } -static void btintel_pcie_copy_tlv(struct sk_buff *skb, enum btintel_pcie_tlv_type type, - void *data, int size) +static void *btintel_pcie_copy_tlv(void *dest, enum btintel_pcie_tlv_type type, + void *data, size_t size) { struct intel_tlv *tlv; - tlv = skb_put(skb, sizeof(*tlv) + size); + tlv = dest; tlv->type = type; tlv->len = size; memcpy(tlv->val, data, tlv->len); + return dest + sizeof(*tlv) + size; } static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) { - u32 offset, prev_size, wr_ptr_status, dump_size, i; + u32 offset, prev_size, wr_ptr_status, dump_size, data_len; struct btintel_pcie_dbgc *dbgc = &data->dbgc; - u8 buf_idx, dump_time_len, fw_build; struct hci_dev *hdev = data->hdev; + u8 *pdata, *p, buf_idx; struct intel_tlv *tlv; struct timespec64 now; - struct sk_buff *skb; struct tm tm_now; - char buf[256]; - u16 hdr_len; - int ret; + char fw_build[128]; + char ts[128]; + char vendor[64]; + char driver[64]; + + if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) + return -EOPNOTSUPP; + wr_ptr_status = btintel_pcie_rd_dev_mem(data, BTINTEL_PCIE_DBGC_CUR_DBGBUFF_STATUS); offset = wr_ptr_status & BTINTEL_PCIE_DBG_OFFSET_BIT_MASK; @@ -657,88 +649,84 @@ static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data) else return -EINVAL; + snprintf(vendor, sizeof(vendor), "Vendor: Intel\n"); + snprintf(driver, sizeof(driver), "Driver: %s\n", + data->dmp_hdr.driver_name); + ktime_get_real_ts64(&now); time64_to_tm(now.tv_sec, 0, &tm_now); - dump_time_len = snprintf(buf, sizeof(buf), "Dump Time: %02d-%02d-%04ld %02d:%02d:%02d", + snprintf(ts, sizeof(ts), "Dump Time: %02d-%02d-%04ld %02d:%02d:%02d", tm_now.tm_mday, tm_now.tm_mon + 1, tm_now.tm_year + 1900, tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec); - fw_build = snprintf(buf + dump_time_len, sizeof(buf) - dump_time_len, + snprintf(fw_build, sizeof(fw_build), "Firmware Timestamp: Year %u WW %02u buildtype %u build %u", 2000 + (data->dmp_hdr.fw_timestamp >> 8), data->dmp_hdr.fw_timestamp & 0xff, data->dmp_hdr.fw_build_type, data->dmp_hdr.fw_build_num); - hdr_len = sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_bt) + - sizeof(*tlv) + sizeof(data->dmp_hdr.write_ptr) + - sizeof(*tlv) + sizeof(data->dmp_hdr.wrap_ctr) + - sizeof(*tlv) + sizeof(data->dmp_hdr.trigger_reason) + - sizeof(*tlv) + sizeof(data->dmp_hdr.fw_git_sha1) + - sizeof(*tlv) + sizeof(data->dmp_hdr.cnvr_top) + - sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_top) + - sizeof(*tlv) + dump_time_len + - sizeof(*tlv) + fw_build; + data_len = sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_bt) + + sizeof(*tlv) + sizeof(data->dmp_hdr.write_ptr) + + sizeof(*tlv) + sizeof(data->dmp_hdr.wrap_ctr) + + sizeof(*tlv) + sizeof(data->dmp_hdr.trigger_reason) + + sizeof(*tlv) + sizeof(data->dmp_hdr.fw_git_sha1) + + sizeof(*tlv) + sizeof(data->dmp_hdr.cnvr_top) + + sizeof(*tlv) + sizeof(data->dmp_hdr.cnvi_top) + + sizeof(*tlv) + strlen(ts) + + sizeof(*tlv) + strlen(fw_build) + + sizeof(*tlv) + strlen(vendor) + + sizeof(*tlv) + strlen(driver); - dump_size = hdr_len + sizeof(hdr_len); + /* + * sizeof(u32) - signature + * sizeof(data_len) - to store tlv data size + * data_len - TLV data + */ + dump_size = sizeof(u32) + sizeof(data_len) + data_len; - skb = alloc_skb(dump_size, GFP_KERNEL); - if (!skb) - return -ENOMEM; /* Add debug buffers data length to dump size */ dump_size += BTINTEL_PCIE_DBGC_BUFFER_SIZE * dbgc->count; - ret = hci_devcd_init(hdev, dump_size); - if (ret) { - bt_dev_err(hdev, "Failed to init devcoredump, err %d", ret); - kfree_skb(skb); - return ret; - } + pdata = vmalloc(dump_size); + if (!pdata) + return -ENOMEM; + p = pdata; - skb_put_data(skb, &hdr_len, sizeof(hdr_len)); + *(u32 *)p = BTINTEL_PCIE_MAGIC_NUM; + p += sizeof(u32); - btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_BT, &data->dmp_hdr.cnvi_bt, - sizeof(data->dmp_hdr.cnvi_bt)); + *(u32 *)p = data_len; + p += sizeof(u32); - btintel_pcie_copy_tlv(skb, BTINTEL_WRITE_PTR, &data->dmp_hdr.write_ptr, - sizeof(data->dmp_hdr.write_ptr)); + + p = btintel_pcie_copy_tlv(p, BTINTEL_VENDOR, vendor, strlen(vendor)); + p = btintel_pcie_copy_tlv(p, BTINTEL_DRIVER, driver, strlen(driver)); + p = btintel_pcie_copy_tlv(p, BTINTEL_DUMP_TIME, ts, strlen(ts)); + p = btintel_pcie_copy_tlv(p, BTINTEL_FW_BUILD, fw_build, + strlen(fw_build)); + p = btintel_pcie_copy_tlv(p, BTINTEL_CNVI_BT, &data->dmp_hdr.cnvi_bt, + sizeof(data->dmp_hdr.cnvi_bt)); + p = btintel_pcie_copy_tlv(p, BTINTEL_WRITE_PTR, &data->dmp_hdr.write_ptr, + sizeof(data->dmp_hdr.write_ptr)); + p = btintel_pcie_copy_tlv(p, BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr, + sizeof(data->dmp_hdr.wrap_ctr)); data->dmp_hdr.wrap_ctr = btintel_pcie_rd_dev_mem(data, BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND); - btintel_pcie_copy_tlv(skb, BTINTEL_WRAP_CTR, &data->dmp_hdr.wrap_ctr, - sizeof(data->dmp_hdr.wrap_ctr)); + p = btintel_pcie_copy_tlv(p, BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason, + sizeof(data->dmp_hdr.trigger_reason)); + p = btintel_pcie_copy_tlv(p, BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1, + sizeof(data->dmp_hdr.fw_git_sha1)); + p = btintel_pcie_copy_tlv(p, BTINTEL_CNVR_TOP, &data->dmp_hdr.cnvr_top, + sizeof(data->dmp_hdr.cnvr_top)); + p = btintel_pcie_copy_tlv(p, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top, + sizeof(data->dmp_hdr.cnvi_top)); - btintel_pcie_copy_tlv(skb, BTINTEL_TRIGGER_REASON, &data->dmp_hdr.trigger_reason, - sizeof(data->dmp_hdr.trigger_reason)); - - btintel_pcie_copy_tlv(skb, BTINTEL_FW_SHA, &data->dmp_hdr.fw_git_sha1, - sizeof(data->dmp_hdr.fw_git_sha1)); - - btintel_pcie_copy_tlv(skb, BTINTEL_CNVR_TOP, &data->dmp_hdr.cnvr_top, - sizeof(data->dmp_hdr.cnvr_top)); - - btintel_pcie_copy_tlv(skb, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top, - sizeof(data->dmp_hdr.cnvi_top)); - - btintel_pcie_copy_tlv(skb, BTINTEL_DUMP_TIME, buf, dump_time_len); - - btintel_pcie_copy_tlv(skb, BTINTEL_FW_BUILD, buf + dump_time_len, fw_build); - - ret = hci_devcd_append(hdev, skb); - if (ret) - goto exit_err; - - for (i = 0; i < dbgc->count; i++) { - ret = btintel_pcie_add_dmp_data(hdev, dbgc->bufs[i].data, - BTINTEL_PCIE_DBGC_BUFFER_SIZE); - if (ret) - break; - } - -exit_err: - hci_devcd_complete(hdev); - return ret; + memcpy(p, dbgc->bufs[0].data, dbgc->count * BTINTEL_PCIE_DBGC_BUFFER_SIZE); + dev_coredumpv(&hdev->dev, pdata, dump_size, GFP_KERNEL); + return 0; } static void btintel_pcie_dump_traces(struct hci_dev *hdev) @@ -760,51 +748,6 @@ static void btintel_pcie_dump_traces(struct hci_dev *hdev) bt_dev_err(hdev, "Failed to dump traces: (%d)", ret); } -static void btintel_pcie_dump_hdr(struct hci_dev *hdev, struct sk_buff *skb) -{ - struct btintel_pcie_data *data = hci_get_drvdata(hdev); - u16 len = skb->len; - u16 *hdrlen_ptr; - char buf[80]; - - hdrlen_ptr = skb_put_zero(skb, sizeof(len)); - - snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n", - INTEL_HW_VARIANT(data->dmp_hdr.cnvi_bt)); - skb_put_data(skb, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Firmware Build Number: %u\n", - data->dmp_hdr.fw_build_num); - skb_put_data(skb, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Driver: %s\n", data->dmp_hdr.driver_name); - skb_put_data(skb, buf, strlen(buf)); - - snprintf(buf, sizeof(buf), "Vendor: Intel\n"); - skb_put_data(skb, buf, strlen(buf)); - - *hdrlen_ptr = skb->len - len; -} - -static void btintel_pcie_dump_notify(struct hci_dev *hdev, int state) -{ - struct btintel_pcie_data *data = hci_get_drvdata(hdev); - - switch (state) { - case HCI_DEVCOREDUMP_IDLE: - data->dmp_hdr.state = HCI_DEVCOREDUMP_IDLE; - break; - case HCI_DEVCOREDUMP_ACTIVE: - data->dmp_hdr.state = HCI_DEVCOREDUMP_ACTIVE; - break; - case HCI_DEVCOREDUMP_TIMEOUT: - case HCI_DEVCOREDUMP_ABORT: - case HCI_DEVCOREDUMP_DONE: - data->dmp_hdr.state = HCI_DEVCOREDUMP_IDLE; - break; - } -} - /* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in * BTINTEL_PCIE_CSR_FUNC_CTRL_REG register and wait for MSI-X with * BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0. @@ -1378,6 +1321,11 @@ static void btintel_pcie_rx_work(struct work_struct *work) struct btintel_pcie_data, rx_work); struct sk_buff *skb; + if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) { + btintel_pcie_dump_traces(data->hdev); + clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags); + } + 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 @@ -1390,11 +1338,6 @@ static void btintel_pcie_rx_work(struct work_struct *work) clear_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags); } - if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) { - btintel_pcie_dump_traces(data->hdev); - clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags); - } - /* Process the sk_buf in queue and send to the HCI layer */ while ((skb = skb_dequeue(&data->rx_skb_q))) { btintel_pcie_recv_frame(data, skb); @@ -2149,6 +2092,7 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev) switch (INTEL_HW_VARIANT(ver_tlv.cnvi_bt)) { case 0x1e: /* BzrI */ case 0x1f: /* ScP */ + case 0x22: /* BzrIW */ /* Display version information of TLV type */ btintel_version_info_tlv(hdev, &ver_tlv); @@ -2184,13 +2128,6 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev) if (ver_tlv.img_type == 0x02 || ver_tlv.img_type == 0x03) data->dmp_hdr.fw_git_sha1 = ver_tlv.git_sha1; - err = hci_devcd_register(hdev, btintel_pcie_dump_traces, btintel_pcie_dump_hdr, - btintel_pcie_dump_notify); - if (err) { - bt_dev_err(hdev, "Failed to register coredump (%d)", err); - goto exit_error; - } - btintel_print_fseq_info(hdev); exit_error: kfree_skb(skb); @@ -2236,6 +2173,7 @@ btintel_pcie_get_recovery(struct pci_dev *pdev, struct device *dev) { struct btintel_pcie_dev_recovery *tmp, *data = NULL; const char *name = pci_name(pdev); + const size_t name_len = strlen(name) + 1; struct hci_dev *hdev = to_hci_dev(dev); spin_lock(&btintel_pcie_recovery_lock); @@ -2252,11 +2190,11 @@ btintel_pcie_get_recovery(struct pci_dev *pdev, struct device *dev) return data; } - data = kzalloc(struct_size(data, name, strlen(name) + 1), GFP_ATOMIC); + data = kzalloc(struct_size(data, name, name_len), GFP_ATOMIC); if (!data) return NULL; - strscpy_pad(data->name, name, strlen(name) + 1); + strscpy(data->name, name, name_len); spin_lock(&btintel_pcie_recovery_lock); list_add_tail(&data->list, &btintel_pcie_recovery_list); spin_unlock(&btintel_pcie_recovery_lock); @@ -2319,7 +2257,6 @@ static void btintel_pcie_removal_work(struct work_struct *wk) btintel_pcie_synchronize_irqs(data); flush_work(&data->rx_work); - flush_work(&data->hdev->dump.dump_rx); bt_dev_dbg(data->hdev, "Release bluetooth interface"); btintel_pcie_release_hdev(data); @@ -2410,6 +2347,13 @@ static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) btintel_pcie_reset(hdev); } +static bool btintel_pcie_wakeup(struct hci_dev *hdev) +{ + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + + return device_may_wakeup(&data->pdev->dev); +} + static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) { int err; @@ -2435,6 +2379,7 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) hdev->set_diag = btintel_set_diag; hdev->set_bdaddr = btintel_set_bdaddr; hdev->reset = btintel_pcie_reset; + hdev->wakeup = btintel_pcie_wakeup; err = hci_register_dev(hdev); if (err < 0) { @@ -2573,11 +2518,100 @@ static void btintel_pcie_coredump(struct device *dev) } #endif +static int btintel_pcie_suspend_late(struct device *dev, pm_message_t mesg) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct btintel_pcie_data *data; + ktime_t start; + u32 dxstate; + int err; + + data = pci_get_drvdata(pdev); + + dxstate = (mesg.event == PM_EVENT_SUSPEND ? + BTINTEL_PCIE_STATE_D3_HOT : BTINTEL_PCIE_STATE_D3_COLD); + + data->gp0_received = false; + + start = ktime_get(); + + /* Refer: 6.4.11.7 -> Platform power management */ + btintel_pcie_wr_sleep_cntrl(data, dxstate); + err = wait_event_timeout(data->gp0_wait_q, data->gp0_received, + msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); + if (err == 0) { + bt_dev_err(data->hdev, + "Timeout (%u ms) on alive interrupt for D3 entry", + BTINTEL_DEFAULT_INTR_TIMEOUT_MS); + return -EBUSY; + } + + bt_dev_dbg(data->hdev, + "device entered into d3 state from d0 in %lld us", + ktime_to_us(ktime_get() - start)); + + return 0; +} + +static int btintel_pcie_suspend(struct device *dev) +{ + return btintel_pcie_suspend_late(dev, PMSG_SUSPEND); +} + +static int btintel_pcie_hibernate(struct device *dev) +{ + return btintel_pcie_suspend_late(dev, PMSG_HIBERNATE); +} + +static int btintel_pcie_freeze(struct device *dev) +{ + return btintel_pcie_suspend_late(dev, PMSG_FREEZE); +} + +static int btintel_pcie_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct btintel_pcie_data *data; + ktime_t start; + int err; + + data = pci_get_drvdata(pdev); + data->gp0_received = false; + + start = ktime_get(); + + /* Refer: 6.4.11.7 -> Platform power management */ + btintel_pcie_wr_sleep_cntrl(data, BTINTEL_PCIE_STATE_D0); + err = wait_event_timeout(data->gp0_wait_q, data->gp0_received, + msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); + if (err == 0) { + bt_dev_err(data->hdev, + "Timeout (%u ms) on alive interrupt for D0 entry", + BTINTEL_DEFAULT_INTR_TIMEOUT_MS); + return -EBUSY; + } + + bt_dev_dbg(data->hdev, + "device entered into d0 state from d3 in %lld us", + ktime_to_us(ktime_get() - start)); + return 0; +} + +static const struct dev_pm_ops btintel_pcie_pm_ops = { + .suspend = btintel_pcie_suspend, + .resume = btintel_pcie_resume, + .freeze = btintel_pcie_freeze, + .thaw = btintel_pcie_resume, + .poweroff = btintel_pcie_hibernate, + .restore = btintel_pcie_resume, +}; + static struct pci_driver btintel_pcie_driver = { .name = KBUILD_MODNAME, .id_table = btintel_pcie_table, .probe = btintel_pcie_probe, .remove = btintel_pcie_remove, + .driver.pm = pm_sleep_ptr(&btintel_pcie_pm_ops), #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 0fa876c5b954..04b21f968ad3 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -132,6 +132,8 @@ enum btintel_pcie_tlv_type { BTINTEL_CNVI_TOP, BTINTEL_DUMP_TIME, BTINTEL_FW_BUILD, + BTINTEL_VENDOR, + BTINTEL_DRIVER }; /* causes for the MBOX interrupts */ diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 4fc673640bfc..50abefba6d04 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -29,7 +29,7 @@ #include #include -#include "h4_recv.h" +#include "hci_uart.h" #include "btmtk.h" #define VERSION "0.1" diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 76995cfcd534..d9b90ea2ad38 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -27,7 +27,7 @@ #include #include -#include "h4_recv.h" +#include "hci_uart.h" #include "btmtk.h" #define VERSION "0.2" diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 76e7f857fb7d..d5153fed0518 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -24,7 +24,7 @@ #include #include -#include "h4_recv.h" +#include "hci_uart.h" #define MANUFACTURER_NXP 37 diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8085fabadde8..5e9ebf0c5312 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -66,6 +66,7 @@ static struct usb_driver btusb_driver; #define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25) #define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26) #define BTUSB_ACTIONS_SEMI BIT(27) +#define BTUSB_BARROT BIT(28) static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -522,6 +523,8 @@ static const struct usb_device_id quirks_table[] = { /* Realtek 8851BU Bluetooth devices */ { USB_DEVICE(0x3625, 0x010b), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x2001, 0x332a), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Realtek 8852AE Bluetooth devices */ { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK | @@ -698,6 +701,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3615), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3633), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x35f5, 0x7922), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, @@ -732,6 +737,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, 0x3627), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3628), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3630), .driver_info = BTUSB_MEDIATEK | @@ -810,6 +817,10 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x0cb5, 0xc547), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + /* Barrot Technology Bluetooth devices */ + { USB_DEVICE(0x33fa, 0x0010), .driver_info = BTUSB_BARROT }, + { USB_DEVICE(0x33fa, 0x0012), .driver_info = BTUSB_BARROT }, + /* Actions Semiconductor ATS2851 based devices */ { USB_DEVICE(0x10d7, 0xb012), .driver_info = BTUSB_ACTIONS_SEMI }, @@ -1192,6 +1203,18 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count) } if (!hci_skb_expect(skb)) { + /* Each chunk should correspond to at least 1 or more + * events so if there are still bytes left that doesn't + * constitute a new event this is likely a bug in the + * controller. + */ + if (count && count < HCI_EVENT_HDR_SIZE) { + bt_dev_warn(data->hdev, + "Unexpected continuation: %d bytes", + count); + count = 0; + } + /* Complete frame */ btusb_recv_event(data, skb); skb = NULL; diff --git a/drivers/bluetooth/h4_recv.h b/drivers/bluetooth/h4_recv.h deleted file mode 100644 index 28cf2d8c2d48..000000000000 --- a/drivers/bluetooth/h4_recv.h +++ /dev/null @@ -1,153 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * - * Generic Bluetooth HCI UART driver - * - * Copyright (C) 2015-2018 Intel Corporation - */ - -#include - -struct h4_recv_pkt { - u8 type; /* Packet type */ - u8 hlen; /* Header length */ - u8 loff; /* Data length offset in header */ - u8 lsize; /* Data length field size */ - u16 maxlen; /* Max overall packet length */ - int (*recv)(struct hci_dev *hdev, struct sk_buff *skb); -}; - -#define H4_RECV_ACL \ - .type = HCI_ACLDATA_PKT, \ - .hlen = HCI_ACL_HDR_SIZE, \ - .loff = 2, \ - .lsize = 2, \ - .maxlen = HCI_MAX_FRAME_SIZE \ - -#define H4_RECV_SCO \ - .type = HCI_SCODATA_PKT, \ - .hlen = HCI_SCO_HDR_SIZE, \ - .loff = 2, \ - .lsize = 1, \ - .maxlen = HCI_MAX_SCO_SIZE - -#define H4_RECV_EVENT \ - .type = HCI_EVENT_PKT, \ - .hlen = HCI_EVENT_HDR_SIZE, \ - .loff = 1, \ - .lsize = 1, \ - .maxlen = HCI_MAX_EVENT_SIZE - -#define H4_RECV_ISO \ - .type = HCI_ISODATA_PKT, \ - .hlen = HCI_ISO_HDR_SIZE, \ - .loff = 2, \ - .lsize = 2, \ - .maxlen = HCI_MAX_FRAME_SIZE - -static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev, - struct sk_buff *skb, - const unsigned char *buffer, - int count, - const struct h4_recv_pkt *pkts, - int pkts_count) -{ - /* Check for error from previous call */ - if (IS_ERR(skb)) - skb = NULL; - - while (count) { - int i, len; - - if (!skb) { - for (i = 0; i < pkts_count; i++) { - if (buffer[0] != (&pkts[i])->type) - continue; - - skb = bt_skb_alloc((&pkts[i])->maxlen, - GFP_ATOMIC); - if (!skb) - return ERR_PTR(-ENOMEM); - - hci_skb_pkt_type(skb) = (&pkts[i])->type; - hci_skb_expect(skb) = (&pkts[i])->hlen; - break; - } - - /* Check for invalid packet type */ - if (!skb) - return ERR_PTR(-EILSEQ); - - count -= 1; - buffer += 1; - } - - len = min_t(uint, hci_skb_expect(skb) - skb->len, count); - skb_put_data(skb, buffer, len); - - count -= len; - buffer += len; - - /* Check for partial packet */ - if (skb->len < hci_skb_expect(skb)) - continue; - - for (i = 0; i < pkts_count; i++) { - if (hci_skb_pkt_type(skb) == (&pkts[i])->type) - break; - } - - if (i >= pkts_count) { - kfree_skb(skb); - return ERR_PTR(-EILSEQ); - } - - if (skb->len == (&pkts[i])->hlen) { - u16 dlen; - - switch ((&pkts[i])->lsize) { - case 0: - /* No variable data length */ - dlen = 0; - break; - case 1: - /* Single octet variable length */ - dlen = skb->data[(&pkts[i])->loff]; - hci_skb_expect(skb) += dlen; - - if (skb_tailroom(skb) < dlen) { - kfree_skb(skb); - return ERR_PTR(-EMSGSIZE); - } - break; - case 2: - /* Double octet variable length */ - dlen = get_unaligned_le16(skb->data + - (&pkts[i])->loff); - hci_skb_expect(skb) += dlen; - - if (skb_tailroom(skb) < dlen) { - kfree_skb(skb); - return ERR_PTR(-EMSGSIZE); - } - break; - default: - /* Unsupported variable length */ - kfree_skb(skb); - return ERR_PTR(-EILSEQ); - } - - if (!dlen) { - /* No more data, complete frame */ - (&pkts[i])->recv(hdev, skb); - skb = NULL; - } - } else { - /* Complete frame */ - (&pkts[i])->recv(hdev, skb); - skb = NULL; - } - } - - return skb; -} diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 664d82d1e613..591abe6d63dd 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -582,6 +582,9 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count) struct bcsp_struct *bcsp = hu->priv; const unsigned char *ptr; + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + return -EUNATCH; + BT_DBG("hu %p count %d rx_state %d rx_count %ld", hu, count, bcsp->rx_state, bcsp->rx_count); diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index e5751f3070b8..d46ed9011ee5 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -272,7 +272,8 @@ void bt_err_ratelimited(const char *fmt, ...); #define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__) #if IS_ENABLED(CONFIG_BT_FEATURE_DEBUG) -#define BT_DBG(fmt, ...) bt_dbg(fmt "\n", ##__VA_ARGS__) +#define BT_DBG(fmt, ...) \ + bt_dbg("%s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__) #else #define BT_DBG(fmt, ...) pr_debug(fmt "\n", ##__VA_ARGS__) #endif diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index df1847b74e55..9ecc70baaca9 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -488,6 +488,7 @@ enum { #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ #define HCI_ACL_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */ #define HCI_LE_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */ +#define HCI_ISO_TX_TIMEOUT usecs_to_jiffies(0x7fffff) /* 8388607 usecs */ /* HCI data types */ #define HCI_COMMAND_PKT 0x01 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6560b32f3125..2924c2bf2a98 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -487,6 +487,7 @@ struct hci_dev { unsigned long acl_last_tx; unsigned long le_last_tx; + unsigned long iso_last_tx; __u8 le_tx_def_phys; __u8 le_rx_def_phys; @@ -1587,16 +1588,18 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, __u16 setting, struct bt_codec *codec, u16 timeout); struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, - __u8 dst_type, struct bt_iso_qos *qos); + __u8 dst_type, struct bt_iso_qos *qos, + u16 timeout); struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, struct bt_iso_qos *qos, - __u8 base_len, __u8 *base); + __u8 base_len, __u8 *base, u16 timeout); struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, - __u8 dst_type, struct bt_iso_qos *qos); + __u8 dst_type, struct bt_iso_qos *qos, + u16 timeout); struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, __u8 sid, struct bt_iso_qos *qos, - __u8 data_len, __u8 *data); + __u8 data_len, __u8 *data, u16 timeout); struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, __u8 sid, struct bt_iso_qos *qos); int hci_conn_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon, diff --git a/include/net/bluetooth/hci_drv.h b/include/net/bluetooth/hci_drv.h index 2f01c44f05ec..3fd6fdbdb02e 100644 --- a/include/net/bluetooth/hci_drv.h +++ b/include/net/bluetooth/hci_drv.h @@ -47,7 +47,7 @@ struct hci_drv_ev_cmd_complete { struct hci_drv_rp_read_info { __u8 driver_name[HCI_DRV_MAX_DRIVER_NAME_LENGTH]; __le16 num_supported_commands; - __le16 supported_commands[]; + __le16 supported_commands[] __counted_by_le(num_supported_commands); } __packed; /* Driver specific OGF (Opcode Group Field) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 3575cd16049a..74edea06985b 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -53,10 +53,15 @@ struct mgmt_hdr { } __packed; struct mgmt_tlv { - __le16 type; - __u8 length; + /* New members MUST be added within the __struct_group() macro below. */ + __struct_group(mgmt_tlv_hdr, __hdr, __packed, + __le16 type; + __u8 length; + ); __u8 value[]; } __packed; +static_assert(offsetof(struct mgmt_tlv, value) == sizeof(struct mgmt_tlv_hdr), + "struct member likely outside of __struct_group()"); struct mgmt_addr_info { bdaddr_t bdaddr; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e524bb59bff2..111f0e37b672 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -924,10 +924,9 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t case CIS_LINK: case BIS_LINK: case PA_LINK: - if (hdev->iso_mtu) - /* Dedicated ISO Buffer exists */ - break; - fallthrough; + if (!hdev->iso_mtu) + return ERR_PTR(-ECONNREFUSED); + break; case LE_LINK: if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU) return ERR_PTR(-ECONNREFUSED); @@ -1540,7 +1539,7 @@ static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos) /* This function requires the caller holds hdev->lock */ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, struct bt_iso_qos *qos, - __u8 base_len, __u8 *base) + __u8 base_len, __u8 *base, u16 timeout) { struct hci_conn *conn; int err; @@ -1582,6 +1581,7 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, conn->state = BT_CONNECT; conn->sid = sid; + conn->conn_timeout = timeout; hci_conn_hold(conn); return conn; @@ -1922,7 +1922,8 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos) } struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, - __u8 dst_type, struct bt_iso_qos *qos) + __u8 dst_type, struct bt_iso_qos *qos, + u16 timeout) { struct hci_conn *cis; @@ -1937,6 +1938,7 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, cis->dst_type = dst_type; cis->iso_qos.ucast.cig = BT_ISO_QOS_CIG_UNSET; cis->iso_qos.ucast.cis = BT_ISO_QOS_CIS_UNSET; + cis->conn_timeout = timeout; } if (cis->state == BT_CONNECTED) @@ -2176,7 +2178,7 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err) struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, struct bt_iso_qos *qos, - __u8 base_len, __u8 *base) + __u8 base_len, __u8 *base, u16 timeout) { struct hci_conn *conn; struct hci_conn *parent; @@ -2197,7 +2199,7 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, base, base_len); /* We need hci_conn object using the BDADDR_ANY as dst */ - conn = hci_add_bis(hdev, dst, sid, qos, base_len, eir); + conn = hci_add_bis(hdev, dst, sid, qos, base_len, eir, timeout); if (IS_ERR(conn)) return conn; @@ -2250,13 +2252,13 @@ static void bis_mark_per_adv(struct hci_conn *conn, void *data) struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type, __u8 sid, struct bt_iso_qos *qos, - __u8 base_len, __u8 *base) + __u8 base_len, __u8 *base, u16 timeout) { struct hci_conn *conn; int err; struct iso_list_data data; - conn = hci_bind_bis(hdev, dst, sid, qos, base_len, base); + conn = hci_bind_bis(hdev, dst, sid, qos, base_len, base, timeout); if (IS_ERR(conn)) return conn; @@ -2299,7 +2301,8 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst, } struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, - __u8 dst_type, struct bt_iso_qos *qos) + __u8 dst_type, struct bt_iso_qos *qos, + u16 timeout) { struct hci_conn *le; struct hci_conn *cis; @@ -2323,7 +2326,7 @@ struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, hci_iso_qos_setup(hdev, le, &qos->ucast.in, le->le_rx_phy ? le->le_rx_phy : hdev->le_rx_def_phys); - cis = hci_bind_cis(hdev, dst, dst_type, qos); + cis = hci_bind_cis(hdev, dst, dst_type, qos, timeout); if (IS_ERR(cis)) { hci_conn_drop(le); return cis; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 55e0722fd066..3418d7b964a1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3267,6 +3267,8 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue, spin_unlock_bh(&queue->lock); } + + bt_dev_dbg(hdev, "chan %p queued %d", chan, skb_queue_len(queue)); } void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) @@ -3298,6 +3300,10 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) hci_skb_pkt_type(skb) = HCI_SCODATA_PKT; skb_queue_tail(&conn->data_q, skb); + + bt_dev_dbg(hdev, "hcon %p queued %d", conn, + skb_queue_len(&conn->data_q)); + queue_work(hdev->workqueue, &hdev->tx_work); } @@ -3357,6 +3363,8 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue, __skb_queue_tail(queue, skb); } while (list); } + + bt_dev_dbg(hdev, "hcon %p queued %d", conn, skb_queue_len(queue)); } void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb) @@ -3399,8 +3407,7 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote) case CIS_LINK: case BIS_LINK: case PA_LINK: - cnt = hdev->iso_mtu ? hdev->iso_cnt : - hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt; + cnt = hdev->iso_cnt; break; default: cnt = 0; @@ -3428,6 +3435,10 @@ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, skb_queue_empty(&c->data_q)) continue; + bt_dev_dbg(hdev, "hcon %p state %s queued %d", c, + state_to_string(c->state), + skb_queue_len(&c->data_q)); + if (c->state != BT_CONNECTED && c->state != BT_CONFIG) continue; @@ -3586,24 +3597,37 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type) { - unsigned long last_tx; + unsigned long timeout; if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) return; switch (type) { + case ACL_LINK: + /* tx timeout must be longer than maximum link supervision + * timeout (40.9 seconds) + */ + timeout = hdev->acl_last_tx + HCI_ACL_TX_TIMEOUT; + break; case LE_LINK: - last_tx = hdev->le_last_tx; + /* tx timeout must be longer than maximum link supervision + * timeout (40.9 seconds) + */ + timeout = hdev->le_last_tx + HCI_ACL_TX_TIMEOUT; + break; + case CIS_LINK: + case BIS_LINK: + case PA_LINK: + /* tx timeout must be longer than the maximum transport latency + * (8.388607 seconds) + */ + timeout = hdev->iso_last_tx + HCI_ISO_TX_TIMEOUT; break; default: - last_tx = hdev->acl_last_tx; - break; + return; } - /* tx timeout must be longer than maximum link supervision timeout - * (40.9 seconds) - */ - if (!cnt && time_after(jiffies, last_tx + HCI_ACL_TX_TIMEOUT)) + if (!cnt && time_after(jiffies, timeout)) hci_link_tx_to(hdev, type); } @@ -3759,12 +3783,16 @@ static void hci_sched_iso(struct hci_dev *hdev, __u8 type) if (!hci_conn_num(hdev, type)) return; - cnt = hdev->iso_pkts ? &hdev->iso_cnt : - hdev->le_pkts ? &hdev->le_cnt : &hdev->acl_cnt; + cnt = &hdev->iso_cnt; + + __check_timeout(hdev, *cnt, type); + while (*cnt && (conn = hci_low_sent(hdev, type, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); + hci_send_conn_frame(hdev, conn, skb); + hdev->iso_last_tx = jiffies; conn->sent++; if (conn->sent == ~0) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fe49e8a7969f..d790b0d4eb9a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4461,19 +4461,9 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, case CIS_LINK: case BIS_LINK: case PA_LINK: - if (hdev->iso_pkts) { - hdev->iso_cnt += count; - if (hdev->iso_cnt > hdev->iso_pkts) - hdev->iso_cnt = hdev->iso_pkts; - } else if (hdev->le_pkts) { - hdev->le_cnt += count; - if (hdev->le_cnt > hdev->le_pkts) - hdev->le_cnt = hdev->le_pkts; - } else { - hdev->acl_cnt += count; - if (hdev->acl_cnt > hdev->acl_pkts) - hdev->acl_cnt = hdev->acl_pkts; - } + hdev->iso_cnt += count; + if (hdev->iso_cnt > hdev->iso_pkts) + hdev->iso_cnt = hdev->iso_pkts; break; default: diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 7a7d49890858..eefdb6134ca5 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -1325,7 +1325,7 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance) { struct hci_cp_le_set_ext_adv_params cp; struct hci_rp_le_set_ext_adv_params rp; - bool connectable; + bool connectable, require_privacy; u32 flags; bdaddr_t random_addr; u8 own_addr_type; @@ -1363,10 +1363,12 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance) return -EPERM; /* Set require_privacy to true only when non-connectable - * advertising is used. In that case it is fine to use a - * non-resolvable private address. + * advertising is used and it is not periodic. + * In that case it is fine to use a non-resolvable private address. */ - err = hci_get_random_address(hdev, !connectable, + require_privacy = !connectable && !(adv && adv->periodic); + + err = hci_get_random_address(hdev, require_privacy, adv_use_rpa(hdev, flags), adv, &own_addr_type, &random_addr); if (err < 0) diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index 5ce823ca3aaf..9b263d061e05 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -91,8 +91,8 @@ static struct sock *iso_get_sock(bdaddr_t *src, bdaddr_t *dst, iso_sock_match_t match, void *data); /* ---- ISO timers ---- */ -#define ISO_CONN_TIMEOUT (HZ * 40) -#define ISO_DISCONN_TIMEOUT (HZ * 2) +#define ISO_CONN_TIMEOUT secs_to_jiffies(20) +#define ISO_DISCONN_TIMEOUT secs_to_jiffies(2) static void iso_conn_free(struct kref *ref) { @@ -111,6 +111,8 @@ static void iso_conn_free(struct kref *ref) /* Ensure no more work items will run since hci_conn has been dropped */ disable_delayed_work_sync(&conn->timeout_work); + kfree_skb(conn->rx_skb); + kfree(conn); } @@ -367,7 +369,8 @@ static int iso_connect_bis(struct sock *sk) if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, iso_pi(sk)->base_len, - iso_pi(sk)->base); + iso_pi(sk)->base, + READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; @@ -376,7 +379,8 @@ static int iso_connect_bis(struct sock *sk) hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst, le_addr_type(iso_pi(sk)->dst_type), iso_pi(sk)->bc_sid, &iso_pi(sk)->qos, - iso_pi(sk)->base_len, iso_pi(sk)->base); + iso_pi(sk)->base_len, iso_pi(sk)->base, + READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; @@ -458,11 +462,19 @@ static int iso_connect_cis(struct sock *sk) goto unlock; } + /* Check if there are available buffers for output/TX. */ + if (iso_pi(sk)->qos.ucast.out.sdu && !hci_iso_count(hdev) && + (hdev->iso_pkts && !hdev->iso_cnt)) { + err = -ENOBUFS; + goto unlock; + } + /* Just bind if DEFER_SETUP has been set */ if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { hcon = hci_bind_cis(hdev, &iso_pi(sk)->dst, le_addr_type(iso_pi(sk)->dst_type), - &iso_pi(sk)->qos); + &iso_pi(sk)->qos, + READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; @@ -470,7 +482,8 @@ static int iso_connect_cis(struct sock *sk) } else { hcon = hci_connect_cis(hdev, &iso_pi(sk)->dst, le_addr_type(iso_pi(sk)->dst_type), - &iso_pi(sk)->qos); + &iso_pi(sk)->qos, + READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock; @@ -750,6 +763,13 @@ static void iso_sock_kill(struct sock *sk) BT_DBG("sk %p state %d", sk, sk->sk_state); + /* Sock is dead, so set conn->sk to NULL to avoid possible UAF */ + if (iso_pi(sk)->conn) { + iso_conn_lock(iso_pi(sk)->conn); + iso_pi(sk)->conn->sk = NULL; + iso_conn_unlock(iso_pi(sk)->conn); + } + /* Kill poor orphan */ bt_sock_unlink(&iso_sk_list, sk); sock_set_flag(sk, SOCK_DEAD); @@ -2407,7 +2427,7 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), skb->len); conn->rx_len -= skb->len; - return; + break; case ISO_END: skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 225140fcb3d6..a3d16eece0d2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4542,13 +4542,11 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, return -ENOMEM; #ifdef CONFIG_BT_FEATURE_DEBUG - if (!hdev) { - flags = bt_dbg_get() ? BIT(0) : 0; + flags = bt_dbg_get() ? BIT(0) : 0; - memcpy(rp->features[idx].uuid, debug_uuid, 16); - rp->features[idx].flags = cpu_to_le32(flags); - idx++; - } + memcpy(rp->features[idx].uuid, debug_uuid, 16); + rp->features[idx].flags = cpu_to_le32(flags); + idx++; #endif if (hdev && hci_dev_le_state_simultaneous(hdev)) { diff --git a/net/bluetooth/mgmt_config.c b/net/bluetooth/mgmt_config.c index 6ef701c27da4..c4063d200c0a 100644 --- a/net/bluetooth/mgmt_config.c +++ b/net/bluetooth/mgmt_config.c @@ -13,13 +13,13 @@ #define HDEV_PARAM_U16(_param_name_) \ struct {\ - struct mgmt_tlv entry; \ + struct mgmt_tlv_hdr entry; \ __le16 value; \ } __packed _param_name_ #define HDEV_PARAM_U8(_param_name_) \ struct {\ - struct mgmt_tlv entry; \ + struct mgmt_tlv_hdr entry; \ __u8 value; \ } __packed _param_name_ diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index d382d980fd9a..ab0cf442d57b 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -498,6 +498,13 @@ static void sco_sock_kill(struct sock *sk) BT_DBG("sk %p state %d", sk, sk->sk_state); + /* Sock is dead, so set conn->sk to NULL to avoid possible UAF */ + if (sco_pi(sk)->conn) { + sco_conn_lock(sco_pi(sk)->conn); + sco_pi(sk)->conn->sk = NULL; + sco_conn_unlock(sco_pi(sk)->conn); + } + /* Kill poor orphan */ bt_sock_unlink(&sco_sk_list, sk); sock_set_flag(sk, SOCK_DEAD);