linux-next: manual merge of the bluetooth tree with the origin tree
From: Mark Brown
Date: Tue Jul 28 2026 - 13:22:16 EST
Hi all,
Today's linux-next merge of the bluetooth tree got a conflict in:
net/bluetooth/hci_sync.c
between commit:
12917f591cea1 ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()")
from the origin tree and commits:
76c2d047410ba ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()")
73b6871b261f3 ("Bluetooth: hci_sync: remove unnecessary hci_conn_get in create_conn_sync")
423e5fc465eb1 ("Bluetooth: hci_sync: fix hci_conn_del() use in hci_le_create_conn_sync")
from the bluetooth tree.
I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging. You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.
diff --combined net/bluetooth/hci_sync.c
index c0b1fc293b496,7779d9d1663a4..0000000000000
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@@ -860,32 -860,6 +860,6 @@@ void hci_cmd_sync_cancel_entry(struct h
}
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
@@@ -1233,10 -1207,11 +1207,11 @@@ static int hci_set_adv_set_random_addr_
}
static int
- hci_set_ext_adv_params_sync(struct hci_dev *hdev, struct adv_info *adv,
+ hci_set_ext_adv_params_sync(struct hci_dev *hdev, u8 instance,
const struct hci_cp_le_set_ext_adv_params *cp,
struct hci_rp_le_set_ext_adv_params *rp)
{
+ struct adv_info *adv;
struct sk_buff *skb;
skb = __hci_cmd_sync(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(*cp),
@@@ -1264,11 -1239,15 +1239,15 @@@
if (!rp->status) {
hdev->adv_addr_type = cp->own_addr_type;
- if (!cp->handle) {
+ if (!instance) {
/* Store in hdev for instance 0 */
hdev->adv_tx_power = rp->tx_power;
- } else if (adv) {
- adv->tx_power = rp->tx_power;
+ } else {
+ hci_dev_lock(hdev);
+ adv = hci_find_adv_instance(hdev, instance);
+ if (adv)
+ adv->tx_power = rp->tx_power;
+ hci_dev_unlock(hdev);
}
}
@@@ -1284,9 -1263,13 +1263,13 @@@ static int hci_set_ext_adv_data_sync(st
int err;
if (instance) {
+ hci_dev_lock(hdev);
+
adv = hci_find_adv_instance(hdev, instance);
- if (!adv || !adv->adv_data_changed)
+ if (!adv || !adv->adv_data_changed) {
+ hci_dev_unlock(hdev);
return 0;
+ }
}
len = eir_create_adv_data(hdev, instance, pdu->data,
@@@ -1297,16 -1280,27 +1280,27 @@@
pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
+ if (adv) {
+ adv->adv_data_changed = false;
+ hci_dev_unlock(hdev);
+ }
+
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
struct_size(pdu, data, len), pdu,
HCI_CMD_TIMEOUT);
- if (err)
- return err;
+ if (err) {
+ if (instance) {
+ hci_dev_lock(hdev);
+ adv = hci_find_adv_instance(hdev, instance);
+ if (adv)
+ adv->adv_data_changed = true;
+ hci_dev_unlock(hdev);
+ }
- /* Update data if the command succeed */
- if (adv) {
- adv->adv_data_changed = false;
- } else {
+ return err;
+ }
+
+ if (!instance) {
memcpy(hdev->adv_data, pdu->data, len);
hdev->adv_data_len = len;
}
@@@ -1360,22 -1354,22 +1354,22 @@@ int hci_setup_ext_adv_instance_sync(str
struct adv_info *adv;
bool secondary_adv;
- if (instance > 0) {
- adv = hci_find_adv_instance(hdev, instance);
- if (!adv)
- return -EINVAL;
- } else {
- adv = NULL;
- }
-
/* Updating parameters of an active instance will return a
- * Command Disallowed error, so we must first disable the
- * instance if it is active.
+ * Command Disallowed error, so disable it before taking a snapshot.
*/
- if (adv) {
+ if (instance > 0) {
err = hci_disable_ext_adv_instance_sync(hdev, instance);
if (err)
return err;
+
+ hci_dev_lock(hdev);
+ adv = hci_find_adv_instance(hdev, instance);
+ if (!adv) {
+ hci_dev_unlock(hdev);
+ return -EINVAL;
+ }
+ } else {
+ adv = NULL;
}
flags = hci_adv_instance_flags(hdev, instance);
@@@ -1386,8 -1380,11 +1380,11 @@@
connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
mgmt_get_connectable(hdev);
- if (!is_advertising_allowed(hdev, connectable))
+ if (!is_advertising_allowed(hdev, connectable)) {
+ if (instance)
+ hci_dev_unlock(hdev);
return -EPERM;
+ }
/* Set require_privacy to true only when non-connectable
* advertising is used and it is not periodic.
@@@ -1398,8 -1395,11 +1395,11 @@@
err = hci_get_random_address(hdev, require_privacy,
adv_use_rpa(hdev, flags), adv,
&own_addr_type, &random_addr);
- if (err < 0)
+ if (err < 0) {
+ if (instance)
+ hci_dev_unlock(hdev);
return err;
+ }
memset(&cp, 0, sizeof(cp));
@@@ -1450,6 -1450,9 +1450,9 @@@
cp.channel_map = hdev->le_adv_channel_map;
cp.handle = adv ? adv->handle : instance;
+ if (instance)
+ hci_dev_unlock(hdev);
+
if (flags & MGMT_ADV_FLAG_SEC_2M) {
cp.primary_phy = HCI_ADV_PHY_1M;
cp.secondary_phy = HCI_ADV_PHY_2M;
@@@ -1462,12 -1465,12 +1465,12 @@@
cp.secondary_phy = HCI_ADV_PHY_1M;
}
- err = hci_set_ext_adv_params_sync(hdev, adv, &cp, &rp);
+ err = hci_set_ext_adv_params_sync(hdev, instance, &cp, &rp);
if (err)
return err;
/* Update adv data as tx power is known now */
- err = hci_set_ext_adv_data_sync(hdev, cp.handle);
+ err = hci_set_ext_adv_data_sync(hdev, instance);
if (err)
return err;
@@@ -1475,9 -1478,14 +1478,14 @@@
own_addr_type == ADDR_LE_DEV_RANDOM_RESOLVED) &&
bacmp(&random_addr, BDADDR_ANY)) {
/* Check if random address need to be updated */
- if (adv) {
- if (!bacmp(&random_addr, &adv->random_addr))
+ if (instance) {
+ hci_dev_lock(hdev);
+ adv = hci_find_adv_instance(hdev, instance);
+ if (!adv || !bacmp(&random_addr, &adv->random_addr)) {
+ hci_dev_unlock(hdev);
return 0;
+ }
+ hci_dev_unlock(hdev);
} else {
if (!bacmp(&random_addr, &hdev->random_addr))
return 0;
@@@ -1499,9 -1507,13 +1507,13 @@@ static int hci_set_ext_scan_rsp_data_sy
int err;
if (instance) {
+ hci_dev_lock(hdev);
+
adv = hci_find_adv_instance(hdev, instance);
- if (!adv || !adv->scan_rsp_changed)
+ if (!adv || !adv->scan_rsp_changed) {
+ hci_dev_unlock(hdev);
return 0;
+ }
}
len = eir_create_scan_rsp(hdev, instance, pdu->data);
@@@ -1511,15 -1523,27 +1523,27 @@@
pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
+ if (adv) {
+ adv->scan_rsp_changed = false;
+ hci_dev_unlock(hdev);
+ }
+
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA,
struct_size(pdu, data, len), pdu,
HCI_CMD_TIMEOUT);
- if (err)
- return err;
+ if (err) {
+ if (instance) {
+ hci_dev_lock(hdev);
+ adv = hci_find_adv_instance(hdev, instance);
+ if (adv)
+ adv->scan_rsp_changed = true;
+ hci_dev_unlock(hdev);
+ }
- if (adv) {
- adv->scan_rsp_changed = false;
- } else {
+ return err;
+ }
+
+ if (!instance) {
memcpy(hdev->scan_rsp_data, pdu->data, len);
hdev->scan_rsp_data_len = len;
}
@@@ -1534,8 -1558,14 +1558,14 @@@ static int __hci_set_scan_rsp_data_sync
memset(&cp, 0, sizeof(cp));
+ if (instance)
+ hci_dev_lock(hdev);
+
len = eir_create_scan_rsp(hdev, instance, cp.data);
+ if (instance)
+ hci_dev_unlock(hdev);
+
if (hdev->scan_rsp_data_len == len &&
!memcmp(cp.data, hdev->scan_rsp_data, len))
return 0;
@@@ -1670,9 -1700,13 +1700,13 @@@ static int hci_set_per_adv_data_sync(st
struct adv_info *adv = NULL;
if (instance) {
+ hci_dev_lock(hdev);
+
adv = hci_find_adv_instance(hdev, instance);
- if (!adv || !adv->periodic)
+ if (!adv || !adv->periodic) {
+ hci_dev_unlock(hdev);
return 0;
+ }
}
len = eir_create_per_adv_data(hdev, instance, pdu->data);
@@@ -1681,6 -1715,9 +1715,9 @@@
pdu->handle = adv ? adv->handle : instance;
pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
+ if (adv)
+ hci_dev_unlock(hdev);
+
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PER_ADV_DATA,
struct_size(pdu, data, len), pdu,
HCI_CMD_TIMEOUT);
@@@ -3717,18 -3754,20 +3754,20 @@@ static const struct hci_init_stage hci_
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;
@@@ -6523,7 -6562,7 +6562,7 @@@ static int hci_le_ext_directed_advertis
if (err)
return err;
- err = hci_set_ext_adv_params_sync(hdev, NULL, &cp, &rp);
+ err = hci_set_ext_adv_params_sync(hdev, 0, &cp, &rp);
if (err)
return err;
@@@ -6678,11 -6717,6 +6717,11 @@@ static int hci_le_create_conn_sync(stru
bt_dev_dbg(hdev, "conn %p", conn);
+ /* Hold a reference so conn stays valid for the HCI_CONN_CREATE
+ * clear_bit() at done.
+ */
+ hci_conn_get(conn);
+
clear_bit(HCI_CONN_SCANNING, &conn->flags);
conn->state = BT_CONNECT;
@@@ -6694,8 -6728,9 +6733,9 @@@
if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
hdev->le_scan_type == LE_SCAN_ACTIVE &&
!hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES)) {
- hci_conn_del(conn);
- hci_conn_put(conn);
+ conn->state = BT_OPEN;
+ hci_abort_conn_sync(hdev, conn,
+ HCI_ERROR_REJ_LIMITED_RESOURCES);
return -EBUSY;
}
@@@ -6793,7 -6828,6 +6833,7 @@@ done
/* Re-enable advertising after the connection attempt is finished. */
hci_resume_advertising_sync(hdev);
+ hci_conn_put(conn);
return err;
}
@@@ -7068,11 -7102,6 +7108,6 @@@ static int hci_acl_create_conn_sync(str
else
cp.role_switch = 0x00;
- /* Hold a reference so conn stays valid for the HCI_CONN_CREATE
- * clear_bit() below.
- */
- hci_conn_get(conn);
-
/* Mark create connection in flight so hci_cancel_connect_sync() can
* cancel it while blocking on the connection complete event.
*/
@@@ -7084,17 -7113,27 +7119,27 @@@
conn->conn_timeout, NULL);
clear_bit(HCI_CONN_CREATE, &conn->flags);
- hci_conn_put(conn);
return err;
}
+ static void hci_acl_create_conn_sync_complete(struct hci_dev *hdev, void *data,
+ int err)
+ {
+ struct hci_conn *conn = data;
+
+ hci_conn_put(conn);
+ }
+
int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
int err;
- err = hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
- NULL);
+ err = hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync,
+ hci_conn_get(conn),
+ hci_acl_create_conn_sync_complete);
+ if (err)
+ hci_conn_put(conn);
return (err == -EEXIST) ? 0 : err;
}
@@@ -7105,36 -7144,41 +7150,41 @@@ static void create_le_conn_complete(str
bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED)
- return;
+ goto done;
hci_dev_lock(hdev);
if (!hci_conn_valid(hdev, conn))
- goto done;
+ goto unlock;
if (!err) {
hci_connect_le_scan_cleanup(conn, 0x00);
- goto done;
+ goto unlock;
}
/* Check if connection is still pending */
if (conn != hci_lookup_le_connect(hdev))
- goto done;
+ goto unlock;
/* Flush to make sure we send create conn cancel command if needed */
flush_delayed_work(&conn->le_conn_timeout);
hci_conn_failed(conn, bt_status(err));
- done:
+ unlock:
hci_dev_unlock(hdev);
+ done:
+ hci_conn_put(conn);
}
int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
int err;
- err = hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
+ err = hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync,
+ hci_conn_get(conn),
create_le_conn_complete);
+ if (err)
+ hci_conn_put(conn);
return (err == -EEXIST) ? 0 : err;
}
@@@ -7257,7 -7301,7 +7307,7 @@@ static void create_pa_complete(struct h
bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED)
- return;
+ goto done;
hci_dev_lock(hdev);
@@@ -7281,6 -7325,8 +7331,8 @@@
unlock:
hci_dev_unlock(hdev);
+ done:
+ hci_conn_put(conn);
}
static int hci_le_past_params_sync(struct hci_dev *hdev, struct hci_conn *conn,
@@@ -7431,8 -7477,11 +7483,11 @@@ int hci_connect_pa_sync(struct hci_dev
{
int err;
- err = hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync, conn,
+ err = hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync,
+ hci_conn_get(conn),
create_pa_complete);
+ if (err)
+ hci_conn_put(conn);
return (err == -EEXIST) ? 0 : err;
}
@@@ -7443,10 -7492,12 +7498,12 @@@ static void create_big_complete(struct
bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED)
- return;
+ goto done;
- if (hci_conn_valid(hdev, conn))
- clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
+ clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
+
+ done:
+ hci_conn_put(conn);
}
static int hci_le_big_create_sync(struct hci_dev *hdev, void *data)
@@@ -7498,8 -7549,14 +7555,14 @@@ int hci_connect_big_sync(struct hci_de
{
int err;
- err = hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
+ if (!conn)
+ return 0;
+
+ err = hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync,
+ hci_conn_get(conn),
create_big_complete);
+ if (err)
+ hci_conn_put(conn);
return (err == -EEXIST) ? 0 : err;
}
@@@ -7514,6 -7571,8 +7577,8 @@@ static void past_complete(struct hci_de
bt_dev_dbg(hdev, "err %d", err);
+ hci_conn_put(past->conn);
+ hci_conn_put(past->le);
kfree(past);
}
@@@ -7578,8 -7637,8 +7643,8 @@@ int hci_past_sync(struct hci_conn *conn
if (!data)
return -ENOMEM;
- data->conn = conn;
- data->le = le;
+ data->conn = hci_conn_get(conn);
+ data->le = hci_conn_get(le);
if (conn->role == HCI_ROLE_MASTER)
err = hci_cmd_sync_queue_once(conn->hdev,
@@@ -7589,8 -7648,11 +7654,11 @@@
err = hci_cmd_sync_queue_once(conn->hdev, hci_le_past_sync,
data, past_complete);
- if (err)
+ if (err) {
+ hci_conn_put(data->conn);
+ hci_conn_put(data->le);
kfree(data);
+ }
return (err == -EEXIST) ? 0 : err;
}
Attachment:
signature.asc
Description: PGP signature