bluetooth pull request for net:

Core:
 
  - hci_core: use skb_get() instead of skb_clone() for req_skb
  - hci_conn: re-enable advertising only for peripheral role
  - hci_event: clear HCI_LE_ADV only on a created connection
  - hci_sync: Clear HCI_CMD_PENDING when dropping the last request
  - hci_sync: add conditional locking annotations
  - hci_sync: do not leak an hci_conn when a second LE connect is rejected
  - eir: Fix OOB read in eir_get_service_data()
  - mgmt: fix 'hdev->discovery.uuids' NULL dereference
  - L2CAP: access chan->conn safely in get/setsockopt
  - L2CAP: reject accept queue add unless BT_LISTEN
  - L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan
  - RFCOMM: serialize security confirmation handling
  - RFCOMM: serialize session teardown
  - RFCOMM: Validate MTU in rfcomm_apply_pn() to prevent infinite loop
  - ISO: fix use-after-free of listener socket in iso_conn_ready
 
 Drivers:
 
  - btnxpuart: Validate the FW dump header length
  - btnxpuart: Check remote M.2 connector availability before pwrseq
  - btmtksdio: Take exclusive ownership of the SKB before TX
  - btmtksdio: Fix out-of-bounds DMA read in the TX path
  - hci_uart: Fix false success return in hci_uart_setup()
  - hci_bcm: fix usage_count leak when autosuspend_delay is negative
  - hci_h5: fix usage_count leak when autosuspend_delay is negative
  - hci_intel: fix usage_count leak when autosuspend_delay is negative
  - btmtk: Do not report success when subsys reset fails
  - btmtk: Do not discard the subsystem reset timeout
  - btusb: limit RTL8761B BROKEN_EXT_SCAN quirk to 0bda:a728
  - hci_bcm4377: Ignore reserved PHY in ext adv reports on BCM4378
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCgA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmqMhYgZHGx1aXoudm9u
 LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKcEvD/9aWqXXH3K6WMwGtRnYUdjd
 LMqf8U/qA4h/hu+zk8+YIcpWkORDG4EWx01ZTZDnOeHi0/XREtEaKNZ6AbP91CXR
 J9ZGUVMAuhJ4SrE3gIBaAqw/1NA1m4ygL5i57tIfIdfgkye6nHPagyVUGWJmBAMr
 QLF8M6WmRghHhvElX69zk640o7v21/XadmpA02/78o/I73BNHBvBdZH/Dd8rGwAI
 +Z4TJ/tSRVJQO15MiutWu92tGMiFt7AN7Bzj1Xv6E+0yiOqCwOfXpGXq6ALGofZy
 5iZ8BHWhvRTtj/4sSU2M9p/sH/dwbBW6CA69QL8CwAMnKPbARHwlx/nI5vXEVWKK
 Cb3ItdG65AoMV4+/vg0VuhbUmXDTk2ZI44KW2sunXcY/aVjA1O6afnIyFcQZ/JSr
 Fp+F/C8ZYtBDJqenX3d6KuHRUJtierkCSjWovetI3ty2BJ07jsb0RLb3BuEeJDtx
 RK1YiOlLTfFVaJCDgGcJ7CcOLlAN6EYv45WtlH395uLdSwNqNbS3GdvwyX2qSTjs
 2MNXLYL0EnnjSBBKuvjl0Z50H5t8OYt+UDcZRiwPO1r4rWlilUC8jS19kH4qiTcm
 PXjtjtfc0PZiKnE5lF7aWY0gNbaPvUHHG/PCZQCd55s3DgKE8y+nap1v7f/5gvMD
 wV4Wga1ecjWjJUbMzGkAoA==
 =q5DT
 -----END PGP SIGNATURE-----

Merge tag 'for-net-2026-08-24' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth

Luiz Augusto von Dentz says:

====================
bluetooth pull request for net:

Core:

 - hci_core: use skb_get() instead of skb_clone() for req_skb
 - hci_conn: re-enable advertising only for peripheral role
 - hci_event: clear HCI_LE_ADV only on a created connection
 - hci_sync: Clear HCI_CMD_PENDING when dropping the last request
 - hci_sync: add conditional locking annotations
 - hci_sync: do not leak an hci_conn when a second LE connect is rejected
 - eir: Fix OOB read in eir_get_service_data()
 - mgmt: fix 'hdev->discovery.uuids' NULL dereference
 - L2CAP: access chan->conn safely in get/setsockopt
 - L2CAP: reject accept queue add unless BT_LISTEN
 - L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan
 - RFCOMM: serialize security confirmation handling
 - RFCOMM: serialize session teardown
 - RFCOMM: Validate MTU in rfcomm_apply_pn() to prevent infinite loop
 - ISO: fix use-after-free of listener socket in iso_conn_ready

Drivers:

 - btnxpuart: Validate the FW dump header length
 - btnxpuart: Check remote M.2 connector availability before pwrseq
 - btmtksdio: Take exclusive ownership of the SKB before TX
 - btmtksdio: Fix out-of-bounds DMA read in the TX path
 - hci_uart: Fix false success return in hci_uart_setup()
 - hci_bcm: fix usage_count leak when autosuspend_delay is negative
 - hci_h5: fix usage_count leak when autosuspend_delay is negative
 - hci_intel: fix usage_count leak when autosuspend_delay is negative
 - btmtk: Do not report success when subsys reset fails
 - btmtk: Do not discard the subsystem reset timeout
 - btusb: limit RTL8761B BROKEN_EXT_SCAN quirk to 0bda:a728
 - hci_bcm4377: Ignore reserved PHY in ext adv reports on BCM4378

* tag 'for-net-2026-08-24' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: (27 commits)
  Bluetooth: RFCOMM: serialize session teardown
  Bluetooth: do not leak an hci_conn when a second LE connect is rejected
  Bluetooth: RFCOMM: serialize security confirmation handling
  Bluetooth: btusb: limit RTL8761B BROKEN_EXT_SCAN quirk to 0bda:a728
  Bluetooth: hci_uart: Fix false success return in hci_uart_setup()
  Bluetooth: RFCOMM: Validate MTU in rfcomm_apply_pn() to prevent infinite loop
  Bluetooth: ISO: fix use-after-free of listener socket in iso_conn_ready
  Bluetooth: hci_core: use skb_get() instead of skb_clone() for req_skb
  Bluetooth: hci_event: clear HCI_LE_ADV only on a created connection
  Bluetooth: hci_conn: re-enable advertising only for peripheral role
  Bluetooth: hci_bcm4377: Ignore reserved PHY in ext adv reports on BCM4378
  Bluetooth: eir: Fix OOB read in eir_get_service_data()
  Bluetooth: btnxpuart: Validate the FW dump header length
  Bluetooth: hci_sync: add conditional locking annotations
  Bluetooth: btnxpuart: Check remote M.2 connector availability before pwrseq
  Bluetooth: btmtksdio: Fix out-of-bounds DMA read in the TX path
  Bluetooth: btmtksdio: Take exclusive ownership of the SKB before TX
  Bluetooth: btmtk: Do not discard the subsystem reset timeout
  Bluetooth: btmtk: Do not report success when subsys reset fails
  Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan
  ...
====================

Link: https://patch.msgid.link/20260824180639.3570348-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-08-24 13:02:35 -07:00
commit b70b7b7156
22 changed files with 222 additions and 75 deletions

View File

@ -860,6 +860,7 @@ static u32 btmtk_usb_reset_done(struct hci_dev *hdev)
int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
{
int reset_err = 0;
u32 val;
int err;
@ -958,8 +959,10 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
err = readx_poll_timeout(btmtk_usb_reset_done, hdev, val,
val & MTK_BT_RST_DONE, 20000, 1000000);
if (err < 0)
if (err < 0) {
bt_dev_err(hdev, "Reset timeout");
reset_err = err;
}
if (dev_id == 0x7922) {
err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT, 0x000000FF);
@ -968,10 +971,12 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
}
err = btmtk_usb_id_get(hdev, 0x70010200, &val);
if (err || (!val && dev_id != 0x6639))
if (err || (!val && dev_id != 0x6639)) {
bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
return err ? err : -ENODEV;
}
return err;
return reset_err;
}
EXPORT_SYMBOL_GPL(btmtk_usb_subsys_reset);

View File

@ -272,12 +272,24 @@ static int btmtksdio_tx_packet(struct btmtksdio_dev *bdev,
struct sk_buff *skb)
{
struct mtkbtsdio_hdr *sdio_hdr;
unsigned int len, pad_len;
int err;
/* Make sure that there are enough rooms for SDIO header */
if (unlikely(skb_headroom(skb) < sizeof(*sdio_hdr))) {
err = pskb_expand_head(skb, sizeof(*sdio_hdr), 0,
GFP_ATOMIC);
/* Make sure that the data buffer is not shared with anyone else and
* that there is enough room for the SDIO header
*/
err = skb_cow_head(skb, sizeof(*sdio_hdr));
if (err < 0)
return err;
/* The transfer is rounded up to the SDIO block size, so the buffer
* has to provide tailroom for the padding as well
*/
len = skb->len + sizeof(*sdio_hdr);
pad_len = round_up(len, MTK_SDIO_BLOCK_SIZE) - len;
if (unlikely(skb_tailroom(skb) < pad_len)) {
err = pskb_expand_head(skb, 0, pad_len, GFP_ATOMIC);
if (err < 0)
return err;
}
@ -290,19 +302,22 @@ static int btmtksdio_tx_packet(struct btmtksdio_dev *bdev,
sdio_hdr->reserved = cpu_to_le16(0);
sdio_hdr->bt_type = hci_skb_pkt_type(skb);
clear_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state);
err = sdio_writesb(bdev->func, MTK_REG_CTDR, skb->data,
round_up(skb->len, MTK_SDIO_BLOCK_SIZE));
if (err < 0)
goto err_skb_pull;
/* Zero the padding so that no uninitialised memory is sent out */
skb_put_zero(skb, pad_len);
bdev->hdev->stat.byte_tx += skb->len;
clear_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state);
err = sdio_writesb(bdev->func, MTK_REG_CTDR, skb->data, skb->len);
if (err < 0)
goto err_skb_restore;
bdev->hdev->stat.byte_tx += len;
kfree_skb(skb);
return 0;
err_skb_pull:
err_skb_restore:
skb_trim(skb, len);
skb_pull(skb, sizeof(*sdio_hdr));
return err;

View File

@ -1359,12 +1359,21 @@ static int nxp_process_fw_dump(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_acl_hdr *acl_hdr = (struct hci_acl_hdr *)skb_pull_data(skb,
sizeof(*acl_hdr));
struct nxp_fw_dump_hdr *fw_dump_hdr = (struct nxp_fw_dump_hdr *)skb->data;
struct nxp_fw_dump_hdr *fw_dump_hdr;
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
__u16 seq_num = __le16_to_cpu(fw_dump_hdr->seq_num);
__u16 buf_len = __le16_to_cpu(fw_dump_hdr->buf_len);
__u16 seq_num;
__u16 buf_len;
int err;
fw_dump_hdr = skb_pull_data(skb, sizeof(*fw_dump_hdr));
if (!fw_dump_hdr) {
bt_dev_warn(hdev, "FW dump: invalid or corrupt fw dump chunk");
goto free_skb;
}
seq_num = __le16_to_cpu(fw_dump_hdr->seq_num);
buf_len = __le16_to_cpu(fw_dump_hdr->buf_len);
if (seq_num == 0x0001) {
if (test_and_set_bit(BTNXPUART_FW_DUMP_IN_PROGRESS, &nxpdev->tx_state)) {
bt_dev_err(hdev, "FW dump already in progress");
@ -1809,6 +1818,28 @@ static void nxp_coredump_notify(struct hci_dev *hdev, int state)
kobject_uevent_env(&serdev->dev.kobj, KOBJ_CHANGE, envp);
}
/*
* Check if the remote M.2 connector device linked via OF graph is present
* and available. This is used to determine whether the pwrseq path should
* be taken. When the remote connector node is disabled (e.g., by a DT
* overlay switching from PCIe WiFi to SDIO WiFi), the pwrseq path is
* skipped, allowing the BT driver to use a direct bluetooth child node
* instead.
*/
static bool nxp_m2_connector_is_available(struct device *dev)
{
struct device_node *ep __free(device_node) =
of_graph_get_next_endpoint(dev_of_node(dev), NULL);
if (!ep)
return false;
struct device_node *remote __free(device_node) =
of_graph_get_remote_port_parent(ep);
return remote && of_device_is_available(remote);
}
static int nxp_serdev_probe(struct serdev_device *serdev)
{
struct hci_dev *hdev;
@ -1863,7 +1894,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
return err;
}
if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) {
if (nxp_m2_connector_is_available(&serdev->ctrl->dev)) {
struct pwrseq_desc *pwrseq;
pwrseq = pwrseq_get(&serdev->ctrl->dev, "uart");

View File

@ -1343,19 +1343,6 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
if (!btrtl_dev->ic_info)
return;
switch (btrtl_dev->project_id) {
case CHIP_ID_8761B:
/* RTL8761B/BU reports HCI version 5.1 but does not support
* the LE Extended Scan commands (Opcode 0x2042), causing
* repeated -EBUSY failures when BlueZ attempts extended
* scanning while a connection is active.
*/
hci_set_quirk(hdev, HCI_QUIRK_BROKEN_EXT_SCAN);
break;
default:
break;
}
switch (btrtl_dev->ic_info->lmp_subver) {
case RTL_ROM_LMP_8703B:
/* 8723CS reports two pages for local ext features,

View File

@ -67,6 +67,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26)
#define BTUSB_ACTIONS_SEMI BIT(27)
#define BTUSB_BARROT BIT(28)
#define BTUSB_BROKEN_EXT_SCAN BIT(29)
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@ -617,6 +618,10 @@ static const struct usb_device_id quirks_table[] = {
{ USB_DEVICE(0x0489, 0xe130), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek 8761BU Bluetooth devices */
{ USB_DEVICE(0x0bda, 0xa728), .driver_info = BTUSB_REALTEK |
BTUSB_BROKEN_EXT_SCAN },
/* Realtek Bluetooth devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
.driver_info = BTUSB_REALTEK },
@ -4401,6 +4406,9 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_INVALID_LE_STATES)
hci_set_quirk(hdev, HCI_QUIRK_BROKEN_LE_STATES);
if (id->driver_info & BTUSB_BROKEN_EXT_SCAN)
hci_set_quirk(hdev, HCI_QUIRK_BROKEN_EXT_SCAN);
if (id->driver_info & BTUSB_DIGIANSWER) {
data->cmdreq_type = USB_TYPE_VENDOR;
hci_set_quirk(hdev, HCI_QUIRK_RESET_ON_CLOSE);

View File

@ -547,6 +547,7 @@ static int bcm_close(struct hci_uart *hu)
if (IS_ENABLED(CONFIG_PM) && bdev->irq_acquired) {
devm_free_irq(bdev->dev, bdev->irq, bdev);
device_init_wakeup(bdev->dev, false);
pm_runtime_dont_use_autosuspend(bdev->dev);
pm_runtime_disable(bdev->dev);
}

View File

@ -2490,6 +2490,7 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = {
.has_bar0_core2_window2 = true,
.broken_mws_transport_config = true,
.broken_le_coded = true,
.broken_le_ext_adv_report_phy = true,
.send_calibration = bcm4378_send_calibration,
.send_ptb = bcm4378_send_ptb,
},

View File

@ -1023,8 +1023,10 @@ static void h5_btrtl_open(struct h5 *h5)
static void h5_btrtl_close(struct h5 *h5)
{
if (!test_bit(H5_WAKEUP_DISABLE, &h5->flags))
if (!test_bit(H5_WAKEUP_DISABLE, &h5->flags)) {
pm_runtime_dont_use_autosuspend(&h5->hu->serdev->dev);
pm_runtime_disable(&h5->hu->serdev->dev);
}
gpiod_set_value_cansleep(h5->device_wake_gpio, 0);
gpiod_set_value_cansleep(h5->enable_gpio, 0);

View File

@ -345,6 +345,7 @@ static int intel_set_power(struct hci_uart *hu, bool powered)
devm_free_irq(&idev->pdev->dev, idev->irq, idev);
device_wakeup_disable(&idev->pdev->dev);
pm_runtime_dont_use_autosuspend(&idev->pdev->dev);
pm_runtime_disable(&idev->pdev->dev);
}
}

View File

@ -457,7 +457,7 @@ static int hci_uart_setup(struct hci_dev *hdev)
if (IS_ERR(skb)) {
BT_ERR("%s: Reading local version information failed (%ld)",
hdev->name, PTR_ERR(skb));
return 0;
return PTR_ERR(skb);
}
if (skb->len != sizeof(*ver)) {

View File

@ -221,7 +221,7 @@ static int hci_uart_setup(struct hci_dev *hdev)
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Reading local version info failed (%ld)",
PTR_ERR(skb));
return 0;
return PTR_ERR(skb);
}
if (skb->len != sizeof(*ver))

View File

@ -935,9 +935,9 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
hdev->discovery.result_filtering = false;
hdev->discovery.report_invalid_rssi = true;
hdev->discovery.rssi = HCI_RSSI_INVALID;
hdev->discovery.uuid_count = 0;
spin_lock(&hdev->discovery.lock);
hdev->discovery.uuid_count = 0;
kfree(hdev->discovery.uuids);
hdev->discovery.uuids = NULL;
spin_unlock(&hdev->discovery.lock);

View File

@ -699,7 +699,12 @@ struct l2cap_rx_busy {
struct l2cap_pinfo {
struct bt_sock bt;
/* With owning sk_socket chan may be read without lock, other access
* should hold lock_sock.
*/
struct l2cap_chan *chan;
struct list_head rx_busy;
};

View File

@ -369,6 +369,7 @@ u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len)
{
const u8 *eir_end = eir + eir_len;
size_t dlen;
while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, &dlen))) {
@ -381,7 +382,7 @@ void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len)
}
eir += dlen;
eir_len -= dlen;
eir_len = eir_end - eir;
}
return NULL;

View File

@ -1391,7 +1391,8 @@ static void hci_le_conn_failed(struct hci_conn *conn, u8 status)
/* Enable advertising in case this was a failed connection
* attempt as a peripheral.
*/
hci_enable_advertising(hdev);
if (conn->role == HCI_ROLE_SLAVE)
hci_enable_advertising(hdev);
}
/* This function requires the caller holds hdev->lock */

View File

@ -4093,7 +4093,7 @@ static int hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND &&
!hci_dev_test_and_set_flag(hdev, HCI_CMD_PENDING)) {
kfree_skb(hdev->req_skb);
hdev->req_skb = skb_clone(hdev->sent_cmd, GFP_KERNEL);
hdev->req_skb = skb_get(hdev->sent_cmd);
}
return err;

View File

@ -5763,10 +5763,11 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
hci_dev_lock(hdev);
hci_store_wake_reason(hdev, bdaddr, bdaddr_type);
/* All controllers implicitly stop advertising in the event of a
* connection, so ensure that the state bit is cleared.
/* Advertising stops when a connection is created. On a failed
* connection it keeps running, so leave the state bit alone.
*/
hci_dev_clear_flag(hdev, HCI_LE_ADV);
if (!status)
hci_dev_clear_flag(hdev, HCI_LE_ADV);
/* Check for existing connection:
*

View File

@ -1287,6 +1287,7 @@ hci_set_ext_adv_params_sync(struct hci_dev *hdev, u8 instance,
}
static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
__context_unsafe(/* conditional locking */)
{
DEFINE_FLEX(struct hci_cp_le_set_ext_adv_data, pdu, data, length,
HCI_MAX_EXT_AD_LENGTH);
@ -1375,6 +1376,7 @@ int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
}
int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
__context_unsafe(/* conditional locking */)
{
struct hci_cp_le_set_ext_adv_params cp;
struct hci_rp_le_set_ext_adv_params rp;
@ -1535,6 +1537,7 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
}
static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
__context_unsafe(/* conditional locking */)
{
DEFINE_FLEX(struct hci_cp_le_set_ext_scan_rsp_data, pdu, data, length,
HCI_MAX_EXT_AD_LENGTH);
@ -1588,6 +1591,7 @@ static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
}
static int __hci_set_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
__context_unsafe(/* conditional locking */)
{
struct hci_cp_le_set_scan_rsp_data cp;
u8 len;
@ -1729,6 +1733,7 @@ static int hci_set_per_adv_params_sync(struct hci_dev *hdev, u8 instance,
}
static int hci_set_per_adv_data_sync(struct hci_dev *hdev, u8 instance)
__context_unsafe(/* conditional locking */)
{
DEFINE_FLEX(struct hci_cp_le_set_per_adv_data, pdu, data, length,
HCI_MAX_PER_AD_LENGTH);
@ -5448,6 +5453,7 @@ int hci_dev_open_sync(struct hci_dev *hdev)
if (hdev->req_skb) {
kfree_skb(hdev->req_skb);
hdev->req_skb = NULL;
hci_dev_clear_flag(hdev, HCI_CMD_PENDING);
}
clear_bit(HCI_RUNNING, &hdev->flags);
@ -5632,6 +5638,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
if (hdev->req_skb) {
kfree_skb(hdev->req_skb);
hdev->req_skb = NULL;
hci_dev_clear_flag(hdev, HCI_CMD_PENDING);
}
clear_bit(HCI_RUNNING, &hdev->flags);
@ -7282,8 +7289,13 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
goto unlock;
}
/* Check if connection is still pending */
if (conn != hci_lookup_le_connect(hdev))
/* Check if this connection is still pending.
*
* hci_lookup_le_connect() returns only the first LE connection
* in BT_CONNECT, which is not necessarily this one when two are
* pending at once, so ask the connection itself.
*/
if (conn->state != BT_CONNECT)
goto unlock;
/* Flush to make sure we send create conn cancel command if needed */

View File

@ -2277,6 +2277,14 @@ static void iso_conn_ready(struct iso_conn *conn)
lock_sock(parent);
/* The listener may have been closed concurrently. */
if (parent->sk_state != BT_LISTEN ||
sock_flag(parent, SOCK_ZAPPED)) {
release_sock(parent);
sock_put(parent);
return;
}
sk = iso_sock_alloc(sock_net(parent), NULL,
BTPROTO_ISO, GFP_ATOMIC, 0);
if (!sk) {

View File

@ -436,11 +436,26 @@ static int l2cap_get_mode(struct l2cap_chan *chan)
return -EINVAL;
}
static struct l2cap_conn *l2cap_chan_conn(struct l2cap_chan *chan)
{
lockdep_assert_held(&chan->lock);
/* l2cap_conn_del() sets FLAG_DEL while holding chan->lock before
* conn->hcon is deleted. If not set and conn is non-NULL, conn->hcon
* remains alive during this chan->lock critical section.
*/
if (test_bit(FLAG_DEL, &chan->flags))
return NULL;
return chan->conn;
}
static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
sockopt_t *sopt)
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct l2cap_conn *conn;
struct l2cap_options opts;
struct l2cap_conninfo cinfo;
int err = 0;
@ -451,6 +466,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
len = sopt->optlen;
l2cap_chan_lock(chan);
lock_sock(sk);
switch (optname) {
@ -537,9 +553,15 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
break;
}
conn = l2cap_chan_conn(chan);
if (!conn) {
err = -ENOTCONN;
break;
}
memset(&cinfo, 0, sizeof(cinfo));
cinfo.hci_handle = chan->conn->hcon->handle;
memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);
cinfo.hci_handle = conn->hcon->handle;
memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);
len = min(len, sizeof(cinfo));
if (copy_to_iter(&cinfo, len, &sopt->iter_out) != len)
@ -553,6 +575,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
}
release_sock(sk);
l2cap_chan_unlock(chan);
return err;
}
@ -561,6 +585,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct l2cap_conn *conn;
struct bt_security sec;
struct bt_power pwr;
int len, mode, err = 0;
@ -578,6 +603,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
len = sopt->optlen;
l2cap_chan_lock(chan);
lock_sock(sk);
switch (optname) {
@ -589,12 +615,14 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
break;
}
conn = l2cap_chan_conn(chan);
memset(&sec, 0, sizeof(sec));
if (chan->conn) {
sec.level = chan->conn->hcon->sec_level;
if (conn) {
sec.level = conn->hcon->sec_level;
if (sk->sk_state == BT_CONNECTED)
sec.key_size = chan->conn->hcon->enc_key_size;
sec.key_size = conn->hcon->enc_key_size;
} else {
sec.level = chan->sec_level;
}
@ -678,12 +706,14 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
break;
case BT_PHY:
if (sk->sk_state != BT_CONNECTED) {
conn = l2cap_chan_conn(chan);
if (sk->sk_state != BT_CONNECTED || !conn) {
err = -ENOTCONN;
break;
}
opt = hci_conn_get_phy(chan->conn->hcon);
opt = hci_conn_get_phy(conn->hcon);
if (copy_to_iter(&opt, sizeof(opt), &sopt->iter_out) !=
sizeof(opt))
@ -719,6 +749,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
}
release_sock(sk);
l2cap_chan_unlock(chan);
return err;
}
@ -749,6 +780,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
BT_DBG("sk %p", sk);
l2cap_chan_lock(chan);
lock_sock(sk);
switch (optname) {
@ -850,6 +882,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
}
release_sock(sk);
l2cap_chan_unlock(chan);
return err;
}
@ -913,6 +946,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
l2cap_chan_lock(chan);
lock_sock(sk);
switch (optname) {
@ -938,11 +972,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
chan->sec_level = sec.level;
if (!chan->conn)
conn = l2cap_chan_conn(chan);
if (!conn)
break;
conn = chan->conn;
/* change security for LE channels */
if (chan->scid == L2CAP_CID_ATT) {
if (smp_conn_security(conn->hcon, sec.level)) {
@ -997,7 +1030,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
}
if (opt == BT_FLUSHABLE_OFF) {
conn = chan->conn;
conn = l2cap_chan_conn(chan);
/* proceed further only when we have l2cap_conn and
No Flush support in the LM */
if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
@ -1083,7 +1117,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
case BT_PHY:
if (sk->sk_state != BT_CONNECTED) {
conn = l2cap_chan_conn(chan);
if (sk->sk_state != BT_CONNECTED || !conn) {
err = -ENOTCONN;
break;
}
@ -1093,10 +1128,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
if (err)
break;
if (!chan->conn)
break;
conn = chan->conn;
err = hci_conn_set_phy(conn->hcon, phys);
break;
@ -1139,6 +1170,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
}
release_sock(sk);
l2cap_chan_unlock(chan);
return err;
}
@ -1312,7 +1344,12 @@ static void l2cap_sock_kill(struct sock *sk)
BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
/* Take lock to synchronize against access without owning sk->sk_socket,
* eg. in l2cap_sock_cleanup_listen(). proto_ops etc. don't need lock.
*/
lock_sock(sk);
l2cap_sock_put_chan(sk);
release_sock(sk);
/* Kill poor orphan */
sock_set_flag(sk, SOCK_DEAD);
@ -1516,14 +1553,10 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
* establish sk_lock -> conn->lock and invert the established
* conn->lock -> chan->lock -> sk_lock order (lockdep deadlock).
*
* Instead, briefly take the child sk lock to fetch and pin its chan.
* l2cap_conn_del() reaches the chan free only via
* l2cap_chan_del() -> l2cap_sock_teardown_cb(), which itself takes
* the child sk lock; holding it across l2cap_chan_hold_unless_zero()
* therefore guarantees the chan cannot be freed while we read and
* pin it (hold_unless_zero() additionally skips a chan already past
* its last reference). We then drop the sk lock before taking
* chan->lock, so sk and chan locks are never held together.
* Instead, briefly take the child sk lock to synchronize vs.
* l2cap_sock_kill that puts l2cap_pi(sk)->chan. We then drop the sk
* lock before taking chan->lock, so sk and chan locks are never held
* together.
*
* Since we cannot call l2cap_chan_close() without conn->lock,
* schedule l2cap_chan_timeout to close the channel; it already
@ -1533,10 +1566,12 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
struct l2cap_chan *chan;
lock_sock_nested(sk, L2CAP_NESTING_NORMAL);
chan = l2cap_chan_hold_unless_zero(l2cap_pi(sk)->chan);
chan = l2cap_pi(sk)->chan;
if (chan)
l2cap_chan_hold(chan);
release_sock(sk);
if (!chan) {
/* l2cap_conn_del() already tearing this child down */
/* Already torn down */
sock_put(sk);
continue;
}
@ -1568,6 +1603,11 @@ static int l2cap_sock_new_connection_cb(struct l2cap_chan *chan,
lock_sock(parent);
if (parent->sk_state != BT_LISTEN) {
release_sock(parent);
return -EINVAL;
}
/* Check for backlog size */
if (sk_acceptq_is_full(parent)) {
BT_DBG("backlog full %d", parent->sk_ack_backlog);
@ -1731,10 +1771,14 @@ static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state,
if (!sk)
return;
lock_sock(sk);
sk->sk_state = state;
if (err)
sk->sk_err = err;
release_sock(sk);
}
static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
@ -1810,6 +1854,8 @@ static void l2cap_sock_resume_cb(struct l2cap_chan *chan)
if (!sk)
return;
lock_sock(sk);
if (test_and_clear_bit(FLAG_PENDING_SECURITY, &chan->flags)) {
sk->sk_state = BT_CONNECTED;
chan->state = BT_CONNECTED;
@ -1817,6 +1863,8 @@ static void l2cap_sock_resume_cb(struct l2cap_chan *chan)
clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
sk->sk_state_change(sk);
release_sock(sk);
}
static void l2cap_sock_set_shutdown_cb(struct l2cap_chan *chan)

View File

@ -6171,6 +6171,7 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
struct mgmt_pending_cmd *cmd;
const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
u16 uuid_count, expected_len;
u8 (*uuids)[16] = NULL;
u8 status;
int err;
@ -6247,12 +6248,10 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
hdev->discovery.result_filtering = true;
hdev->discovery.type = cp->type;
hdev->discovery.rssi = cp->rssi;
hdev->discovery.uuid_count = uuid_count;
if (uuid_count > 0) {
hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
GFP_KERNEL);
if (!hdev->discovery.uuids) {
uuids = kmemdup(cp->uuids, uuid_count * sizeof(*uuids), GFP_KERNEL);
if (!uuids) {
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_START_SERVICE_DISCOVERY,
MGMT_STATUS_FAILED,
@ -6262,6 +6261,11 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
}
}
spin_lock(&hdev->discovery.lock);
hdev->discovery.uuids = uuids;
hdev->discovery.uuid_count = uuid_count;
spin_unlock(&hdev->discovery.lock);
err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
start_discovery_complete);
if (err < 0) {
@ -10505,6 +10509,7 @@ static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
!hci_test_quirk(hdev, HCI_QUIRK_STRICT_DUPLICATE_FILTER))))
return false;
spin_lock(&hdev->discovery.lock);
if (hdev->discovery.uuid_count != 0) {
/* If a list of UUIDs is provided in filter, results with no
* matching UUID should be dropped.
@ -10513,9 +10518,12 @@ static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
hdev->discovery.uuids) &&
!eir_has_uuids(scan_rsp, scan_rsp_len,
hdev->discovery.uuid_count,
hdev->discovery.uuids))
hdev->discovery.uuids)) {
spin_unlock(&hdev->discovery.lock);
return false;
}
}
spin_unlock(&hdev->discovery.lock);
/* If duplicate filtering does not report RSSI changes, then restart
* scanning to ensure updated result with updated RSSI values.

View File

@ -1455,6 +1455,10 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
d->mtu = __le16_to_cpu(pn->mtu);
/* MTU 0 causes an infinite loop when fragmenting in sendmsg */
if (!d->mtu)
d->mtu = RFCOMM_DEFAULT_MTU;
if (cr && d->mtu > s->mtu)
d->mtu = s->mtu;
@ -2178,8 +2182,10 @@ static void rfcomm_kill_listener(void)
BT_DBG("");
rfcomm_lock();
list_for_each_entry_safe(s, n, &session_list, list)
rfcomm_session_del(s);
rfcomm_unlock();
}
static int rfcomm_run(void *unused)
@ -2213,9 +2219,13 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
BT_DBG("conn %p status 0x%02x encrypt 0x%02x", conn, status, encrypt);
rfcomm_lock();
s = rfcomm_session_get(&conn->hdev->bdaddr, &conn->dst);
if (!s)
if (!s) {
rfcomm_unlock();
return;
}
list_for_each_entry_safe(d, n, &s->dlcs, list) {
if (test_and_clear_bit(RFCOMM_SEC_PENDING, &d->flags)) {
@ -2247,6 +2257,8 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
}
rfcomm_unlock();
rfcomm_schedule();
}