2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

bluetooth pull request for net:

- hci_conn: Make unacked packet handling more robust
  - hci_event: Treat UNKNOWN_CONN_ID on disconnect as success
  - hci_event: Mark connection as closed during suspend disconnect
  - hci_event: Detect if HCI_EV_NUM_COMP_PKTS is unbalanced
  - hci_event: Disconnect device when BIG sync is lost
  - hci_sync: fix set_local_name race condition
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCgA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmiosHUZHGx1aXoudm9u
 LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKXtCD/92xuS5xvFhqhzexyXPyHa8
 rNB8Gl9EpXlSkftmKwguRxo6LzM8U2R4zOx49MwCVFpcTdWYCP1WvDuWWKcmfuDg
 qyFIUyZWb8u02nRbscwN/yF0YcHwPXpAcWt8XmQvPu9sZ3i0dmJBSrabdZ+OI4oa
 Lqi4frdfWVFr46dpj9U61bWtY34lR+1BxWiOHtLT8+xGlgiugnXwkcwDY7bzmK6s
 hMabAoMCWv5iuWwE8LXubPYHg4M8PPrQORBQ/iNwJYtan7YD6f/sDd3rHlCF8cuU
 uvoCVXDx1UI7LrYsocb9iNHFsyvZD93W5xmK+8PAZKsMZgEcdfs3jLlT6zek/GI/
 ab5nr6q+XVas3Z0tq3MblpAzRmlOZaLM97LqotQC4EBVyIH3JXhwN41nBDKycmM4
 WBPWHZIsJ6ZIV+++tZIIuKAaZHSCiYcEwEiQyV06QdHoDfw9Wc39sr13IOqThXfv
 AOCwjnjUTuqZ6HnmogOcN87tYXQghJ12XJgNgFbxeoAtxqL1TDWtZKJkHB7oHY3l
 gGeN2ffRP+yoXPT7GWQoGAydKylf6fIPkRo64gbEoYmPy56djUZ2lnRMbrYm1MWR
 Yy4SaZhu84jLKdOsLxhRzZR2FxO3E568t2nDDA5xz2F4FkrP8/ih+fOO18+5UVK9
 302cU7sOXc+aSt8LHP4lRQ==
 =4eUN
 -----END PGP SIGNATURE-----

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

Luiz Augusto von Dentz says:

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

* tag 'for-net-2025-08-22' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: hci_sync: fix set_local_name race condition
  Bluetooth: hci_event: Disconnect device when BIG sync is lost
  Bluetooth: hci_event: Detect if HCI_EV_NUM_COMP_PKTS is unbalanced
  Bluetooth: hci_event: Mark connection as closed during suspend disconnect
  Bluetooth: hci_event: Treat UNKNOWN_CONN_ID on disconnect as success
  Bluetooth: hci_conn: Make unacked packet handling more robust
====================

Link: https://patch.msgid.link/20250822180230.345979-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2025-08-22 16:09:12 -07:00
commit 1559c9c231
5 changed files with 75 additions and 25 deletions

View File

@ -93,7 +93,7 @@ int hci_update_class_sync(struct hci_dev *hdev);
int hci_update_eir_sync(struct hci_dev *hdev);
int hci_update_class_sync(struct hci_dev *hdev);
int hci_update_name_sync(struct hci_dev *hdev);
int hci_update_name_sync(struct hci_dev *hdev, const u8 *name);
int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode);
int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,

View File

@ -149,8 +149,6 @@ static void hci_conn_cleanup(struct hci_conn *conn)
hci_chan_list_flush(conn);
hci_conn_hash_del(hdev, conn);
if (HCI_CONN_HANDLE_UNSET(conn->handle))
ida_free(&hdev->unset_handle_ida, conn->handle);
@ -1152,28 +1150,54 @@ void hci_conn_del(struct hci_conn *conn)
disable_delayed_work_sync(&conn->auto_accept_work);
disable_delayed_work_sync(&conn->idle_work);
if (conn->type == ACL_LINK) {
/* Unacked frames */
hdev->acl_cnt += conn->sent;
} else if (conn->type == LE_LINK) {
cancel_delayed_work(&conn->le_conn_timeout);
/* Remove the connection from the list so unacked logic can detect when
* a certain pool is not being utilized.
*/
hci_conn_hash_del(hdev, conn);
if (hdev->le_pkts)
hdev->le_cnt += conn->sent;
/* Handle unacked frames:
*
* - In case there are no connection, or if restoring the buffers
* considered in transist would overflow, restore all buffers to the
* pool.
* - Otherwise restore just the buffers considered in transit for the
* hci_conn
*/
switch (conn->type) {
case ACL_LINK:
if (!hci_conn_num(hdev, ACL_LINK) ||
hdev->acl_cnt + conn->sent > hdev->acl_pkts)
hdev->acl_cnt = hdev->acl_pkts;
else
hdev->acl_cnt += conn->sent;
} else {
/* Unacked ISO frames */
if (conn->type == CIS_LINK ||
conn->type == BIS_LINK ||
conn->type == PA_LINK) {
if (hdev->iso_pkts)
hdev->iso_cnt += conn->sent;
else if (hdev->le_pkts)
break;
case LE_LINK:
cancel_delayed_work(&conn->le_conn_timeout);
if (hdev->le_pkts) {
if (!hci_conn_num(hdev, LE_LINK) ||
hdev->le_cnt + conn->sent > hdev->le_pkts)
hdev->le_cnt = hdev->le_pkts;
else
hdev->le_cnt += conn->sent;
} else {
if ((!hci_conn_num(hdev, LE_LINK) &&
!hci_conn_num(hdev, ACL_LINK)) ||
hdev->acl_cnt + conn->sent > hdev->acl_pkts)
hdev->acl_cnt = hdev->acl_pkts;
else
hdev->acl_cnt += conn->sent;
}
break;
case CIS_LINK:
case BIS_LINK:
case PA_LINK:
if (!hci_iso_count(hdev) ||
hdev->iso_cnt + conn->sent > hdev->iso_pkts)
hdev->iso_cnt = hdev->iso_pkts;
else
hdev->iso_cnt += conn->sent;
break;
}
skb_queue_purge(&conn->data_q);

View File

@ -2703,7 +2703,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
if (!conn)
goto unlock;
if (status) {
if (status && status != HCI_ERROR_UNKNOWN_CONN_ID) {
mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, status);
@ -2718,6 +2718,12 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
goto done;
}
/* During suspend, mark connection as closed immediately
* since we might not receive HCI_EV_DISCONN_COMPLETE
*/
if (hdev->suspended)
conn->state = BT_CLOSED;
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
if (conn->type == ACL_LINK) {
@ -4398,7 +4404,17 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,
if (!conn)
continue;
conn->sent -= count;
/* Check if there is really enough packets outstanding before
* attempting to decrease the sent counter otherwise it could
* underflow..
*/
if (conn->sent >= count) {
conn->sent -= count;
} else {
bt_dev_warn(hdev, "hcon %p sent %u < count %u",
conn, conn->sent, count);
conn->sent = 0;
}
for (i = 0; i < count; ++i)
hci_conn_tx_dequeue(conn);
@ -7008,6 +7024,7 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data,
{
struct hci_evt_le_big_sync_lost *ev = data;
struct hci_conn *bis, *conn;
bool mgmt_conn;
bt_dev_dbg(hdev, "big handle 0x%2.2x", ev->handle);
@ -7026,6 +7043,10 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data,
while ((bis = hci_conn_hash_lookup_big_state(hdev, ev->handle,
BT_CONNECTED,
HCI_ROLE_SLAVE))) {
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &bis->flags);
mgmt_device_disconnected(hdev, &bis->dst, bis->type, bis->dst_type,
ev->reason, mgmt_conn);
clear_bit(HCI_CONN_BIG_SYNC, &bis->flags);
hci_disconn_cfm(bis, ev->reason);
hci_conn_del(bis);

View File

@ -3481,13 +3481,13 @@ int hci_update_scan_sync(struct hci_dev *hdev)
return hci_write_scan_enable_sync(hdev, scan);
}
int hci_update_name_sync(struct hci_dev *hdev)
int hci_update_name_sync(struct hci_dev *hdev, const u8 *name)
{
struct hci_cp_write_local_name cp;
memset(&cp, 0, sizeof(cp));
memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
memcpy(cp.name, name, sizeof(cp.name));
return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LOCAL_NAME,
sizeof(cp), &cp,
@ -3540,7 +3540,7 @@ int hci_powered_update_sync(struct hci_dev *hdev)
hci_write_fast_connectable_sync(hdev, false);
hci_update_scan_sync(hdev);
hci_update_class_sync(hdev);
hci_update_name_sync(hdev);
hci_update_name_sync(hdev, hdev->dev_name);
hci_update_eir_sync(hdev);
}

View File

@ -3892,8 +3892,11 @@ static void set_name_complete(struct hci_dev *hdev, void *data, int err)
static int set_name_sync(struct hci_dev *hdev, void *data)
{
struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_set_local_name *cp = cmd->param;
if (lmp_bredr_capable(hdev)) {
hci_update_name_sync(hdev);
hci_update_name_sync(hdev, cp->name);
hci_update_eir_sync(hdev);
}
@ -9705,7 +9708,9 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
if (!mgmt_connected)
return;
if (link_type != ACL_LINK && link_type != LE_LINK)
if (link_type != ACL_LINK &&
link_type != LE_LINK &&
link_type != BIS_LINK)
return;
bacpy(&ev.addr.bdaddr, bdaddr);