Commit 365af7ac authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'for-net-2024-03-29' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth

Luiz Augusto von Dentz says:

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

 - Bluetooth: Fix TOCTOU in HCI debugfs implementation
 - Bluetooth: hci_event: set the conn encrypted before conn establishes
 - Bluetooth: qca: fix device-address endianness
 - Bluetooth: hci_sync: Fix not checking error on hci_cmd_sync_cancel_sync

* tag 'for-net-2024-03-29' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: Fix TOCTOU in HCI debugfs implementation
  Bluetooth: hci_event: set the conn encrypted before conn establishes
  Bluetooth: hci_sync: Fix not checking error on hci_cmd_sync_cancel_sync
  Bluetooth: qca: fix device-address endianness
  Bluetooth: add quirk for broken address properties
  arm64: dts: qcom: sc7180-trogdor: mark bluetooth address as broken
  dt-bindings: bluetooth: add 'qcom,local-bd-address-broken'
  Revert "Bluetooth: hci_qca: Set BDA quirk bit if fwnode exists in DT"
====================

Link: https://lore.kernel.org/r/20240329140453.2016486-1-luiz.dentz@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents ec7ef3ea 7835fcfd
...@@ -94,6 +94,10 @@ properties: ...@@ -94,6 +94,10 @@ properties:
local-bd-address: true local-bd-address: true
qcom,local-bd-address-broken:
type: boolean
description:
boot firmware is incorrectly passing the address in big-endian order
required: required:
- compatible - compatible
......
...@@ -944,6 +944,8 @@ bluetooth: bluetooth { ...@@ -944,6 +944,8 @@ bluetooth: bluetooth {
vddrf-supply = <&pp1300_l2c>; vddrf-supply = <&pp1300_l2c>;
vddch0-supply = <&pp3300_l10c>; vddch0-supply = <&pp3300_l10c>;
max-speed = <3200000>; max-speed = <3200000>;
qcom,local-bd-address-broken;
}; };
}; };
......
...@@ -826,11 +826,15 @@ EXPORT_SYMBOL_GPL(qca_uart_setup); ...@@ -826,11 +826,15 @@ EXPORT_SYMBOL_GPL(qca_uart_setup);
int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{ {
bdaddr_t bdaddr_swapped;
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6, bdaddr, baswap(&bdaddr_swapped, bdaddr);
HCI_EV_VENDOR, HCI_INIT_TIMEOUT);
skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6,
&bdaddr_swapped, HCI_EV_VENDOR,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) { if (IS_ERR(skb)) {
err = PTR_ERR(skb); err = PTR_ERR(skb);
bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err); bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err);
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
* *
* Copyright (C) 2007 Texas Instruments, Inc. * Copyright (C) 2007 Texas Instruments, Inc.
* Copyright (c) 2010, 2012, 2018 The Linux Foundation. All rights reserved. * Copyright (c) 2010, 2012, 2018 The Linux Foundation. All rights reserved.
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
* *
* Acknowledgements: * Acknowledgements:
* This file is based on hci_ll.c, which was... * This file is based on hci_ll.c, which was...
...@@ -226,6 +225,7 @@ struct qca_serdev { ...@@ -226,6 +225,7 @@ struct qca_serdev {
struct qca_power *bt_power; struct qca_power *bt_power;
u32 init_speed; u32 init_speed;
u32 oper_speed; u32 oper_speed;
bool bdaddr_property_broken;
const char *firmware_name; const char *firmware_name;
}; };
...@@ -1843,6 +1843,7 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1843,6 +1843,7 @@ static int qca_setup(struct hci_uart *hu)
const char *firmware_name = qca_get_firmware_name(hu); const char *firmware_name = qca_get_firmware_name(hu);
int ret; int ret;
struct qca_btsoc_version ver; struct qca_btsoc_version ver;
struct qca_serdev *qcadev;
const char *soc_name; const char *soc_name;
ret = qca_check_speeds(hu); ret = qca_check_speeds(hu);
...@@ -1904,16 +1905,11 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1904,16 +1905,11 @@ static int qca_setup(struct hci_uart *hu)
case QCA_WCN6750: case QCA_WCN6750:
case QCA_WCN6855: case QCA_WCN6855:
case QCA_WCN7850: case QCA_WCN7850:
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
/* Set BDA quirk bit for reading BDA value from fwnode property qcadev = serdev_device_get_drvdata(hu->serdev);
* only if that property exist in DT. if (qcadev->bdaddr_property_broken)
*/ set_bit(HCI_QUIRK_BDADDR_PROPERTY_BROKEN, &hdev->quirks);
if (fwnode_property_present(dev_fwnode(hdev->dev.parent), "local-bd-address")) {
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
bt_dev_info(hdev, "setting quirk bit to read BDA from fwnode later");
} else {
bt_dev_dbg(hdev, "local-bd-address` is not present in the devicetree so not setting quirk bit for BDA");
}
hci_set_aosp_capable(hdev); hci_set_aosp_capable(hdev);
...@@ -2295,6 +2291,9 @@ static int qca_serdev_probe(struct serdev_device *serdev) ...@@ -2295,6 +2291,9 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (!qcadev->oper_speed) if (!qcadev->oper_speed)
BT_DBG("UART will pick default operating speed"); BT_DBG("UART will pick default operating speed");
qcadev->bdaddr_property_broken = device_property_read_bool(&serdev->dev,
"qcom,local-bd-address-broken");
if (data) if (data)
qcadev->btsoc_type = data->soc_type; qcadev->btsoc_type = data->soc_type;
else else
......
...@@ -176,6 +176,15 @@ enum { ...@@ -176,6 +176,15 @@ enum {
*/ */
HCI_QUIRK_USE_BDADDR_PROPERTY, HCI_QUIRK_USE_BDADDR_PROPERTY,
/* When this quirk is set, the Bluetooth Device Address provided by
* the 'local-bd-address' fwnode property is incorrectly specified in
* big-endian order.
*
* This quirk can be set before hci_register_dev is called or
* during the hdev->setup vendor callback.
*/
HCI_QUIRK_BDADDR_PROPERTY_BROKEN,
/* When this quirk is set, the duplicate filtering during /* When this quirk is set, the duplicate filtering during
* scanning is based on Bluetooth devices addresses. To allow * scanning is based on Bluetooth devices addresses. To allow
* RSSI based updates, restart scanning if needed. * RSSI based updates, restart scanning if needed.
......
...@@ -2874,7 +2874,7 @@ static void hci_cancel_cmd_sync(struct hci_dev *hdev, int err) ...@@ -2874,7 +2874,7 @@ static void hci_cancel_cmd_sync(struct hci_dev *hdev, int err)
cancel_delayed_work_sync(&hdev->ncmd_timer); cancel_delayed_work_sync(&hdev->ncmd_timer);
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
hci_cmd_sync_cancel_sync(hdev, -err); hci_cmd_sync_cancel_sync(hdev, err);
} }
/* Suspend HCI device */ /* Suspend HCI device */
...@@ -2894,7 +2894,7 @@ int hci_suspend_dev(struct hci_dev *hdev) ...@@ -2894,7 +2894,7 @@ int hci_suspend_dev(struct hci_dev *hdev)
return 0; return 0;
/* Cancel potentially blocking sync operation before suspend */ /* Cancel potentially blocking sync operation before suspend */
hci_cancel_cmd_sync(hdev, -EHOSTDOWN); hci_cancel_cmd_sync(hdev, EHOSTDOWN);
hci_req_sync_lock(hdev); hci_req_sync_lock(hdev);
ret = hci_suspend_sync(hdev); ret = hci_suspend_sync(hdev);
...@@ -4210,7 +4210,7 @@ static void hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -4210,7 +4210,7 @@ static void hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
err = hci_send_frame(hdev, skb); err = hci_send_frame(hdev, skb);
if (err < 0) { if (err < 0) {
hci_cmd_sync_cancel_sync(hdev, err); hci_cmd_sync_cancel_sync(hdev, -err);
return; return;
} }
......
...@@ -218,10 +218,12 @@ static int conn_info_min_age_set(void *data, u64 val) ...@@ -218,10 +218,12 @@ static int conn_info_min_age_set(void *data, u64 val)
{ {
struct hci_dev *hdev = data; struct hci_dev *hdev = data;
if (val == 0 || val > hdev->conn_info_max_age) hci_dev_lock(hdev);
if (val == 0 || val > hdev->conn_info_max_age) {
hci_dev_unlock(hdev);
return -EINVAL; return -EINVAL;
}
hci_dev_lock(hdev);
hdev->conn_info_min_age = val; hdev->conn_info_min_age = val;
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -246,10 +248,12 @@ static int conn_info_max_age_set(void *data, u64 val) ...@@ -246,10 +248,12 @@ static int conn_info_max_age_set(void *data, u64 val)
{ {
struct hci_dev *hdev = data; struct hci_dev *hdev = data;
if (val == 0 || val < hdev->conn_info_min_age) hci_dev_lock(hdev);
if (val == 0 || val < hdev->conn_info_min_age) {
hci_dev_unlock(hdev);
return -EINVAL; return -EINVAL;
}
hci_dev_lock(hdev);
hdev->conn_info_max_age = val; hdev->conn_info_max_age = val;
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -567,10 +571,12 @@ static int sniff_min_interval_set(void *data, u64 val) ...@@ -567,10 +571,12 @@ static int sniff_min_interval_set(void *data, u64 val)
{ {
struct hci_dev *hdev = data; struct hci_dev *hdev = data;
if (val == 0 || val % 2 || val > hdev->sniff_max_interval) hci_dev_lock(hdev);
if (val == 0 || val % 2 || val > hdev->sniff_max_interval) {
hci_dev_unlock(hdev);
return -EINVAL; return -EINVAL;
}
hci_dev_lock(hdev);
hdev->sniff_min_interval = val; hdev->sniff_min_interval = val;
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -595,10 +601,12 @@ static int sniff_max_interval_set(void *data, u64 val) ...@@ -595,10 +601,12 @@ static int sniff_max_interval_set(void *data, u64 val)
{ {
struct hci_dev *hdev = data; struct hci_dev *hdev = data;
if (val == 0 || val % 2 || val < hdev->sniff_min_interval) hci_dev_lock(hdev);
if (val == 0 || val % 2 || val < hdev->sniff_min_interval) {
hci_dev_unlock(hdev);
return -EINVAL; return -EINVAL;
}
hci_dev_lock(hdev);
hdev->sniff_max_interval = val; hdev->sniff_max_interval = val;
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -850,10 +858,12 @@ static int conn_min_interval_set(void *data, u64 val) ...@@ -850,10 +858,12 @@ static int conn_min_interval_set(void *data, u64 val)
{ {
struct hci_dev *hdev = data; struct hci_dev *hdev = data;
if (val < 0x0006 || val > 0x0c80 || val > hdev->le_conn_max_interval) hci_dev_lock(hdev);
if (val < 0x0006 || val > 0x0c80 || val > hdev->le_conn_max_interval) {
hci_dev_unlock(hdev);
return -EINVAL; return -EINVAL;
}
hci_dev_lock(hdev);
hdev->le_conn_min_interval = val; hdev->le_conn_min_interval = val;
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -878,10 +888,12 @@ static int conn_max_interval_set(void *data, u64 val) ...@@ -878,10 +888,12 @@ static int conn_max_interval_set(void *data, u64 val)
{ {
struct hci_dev *hdev = data; struct hci_dev *hdev = data;
if (val < 0x0006 || val > 0x0c80 || val < hdev->le_conn_min_interval) hci_dev_lock(hdev);
if (val < 0x0006 || val > 0x0c80 || val < hdev->le_conn_min_interval) {
hci_dev_unlock(hdev);
return -EINVAL; return -EINVAL;
}
hci_dev_lock(hdev);
hdev->le_conn_max_interval = val; hdev->le_conn_max_interval = val;
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -990,10 +1002,12 @@ static int adv_min_interval_set(void *data, u64 val) ...@@ -990,10 +1002,12 @@ static int adv_min_interval_set(void *data, u64 val)
{ {
struct hci_dev *hdev = data; struct hci_dev *hdev = data;
if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval) hci_dev_lock(hdev);
if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval) {
hci_dev_unlock(hdev);
return -EINVAL; return -EINVAL;
}
hci_dev_lock(hdev);
hdev->le_adv_min_interval = val; hdev->le_adv_min_interval = val;
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -1018,10 +1032,12 @@ static int adv_max_interval_set(void *data, u64 val) ...@@ -1018,10 +1032,12 @@ static int adv_max_interval_set(void *data, u64 val)
{ {
struct hci_dev *hdev = data; struct hci_dev *hdev = data;
if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval) hci_dev_lock(hdev);
if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval) {
hci_dev_unlock(hdev);
return -EINVAL; return -EINVAL;
}
hci_dev_lock(hdev);
hdev->le_adv_max_interval = val; hdev->le_adv_max_interval = val;
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
......
...@@ -3208,6 +3208,31 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, ...@@ -3208,6 +3208,31 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
if (test_bit(HCI_ENCRYPT, &hdev->flags)) if (test_bit(HCI_ENCRYPT, &hdev->flags))
set_bit(HCI_CONN_ENCRYPT, &conn->flags); set_bit(HCI_CONN_ENCRYPT, &conn->flags);
/* "Link key request" completed ahead of "connect request" completes */
if (ev->encr_mode == 1 && !test_bit(HCI_CONN_ENCRYPT, &conn->flags) &&
ev->link_type == ACL_LINK) {
struct link_key *key;
struct hci_cp_read_enc_key_size cp;
key = hci_find_link_key(hdev, &ev->bdaddr);
if (key) {
set_bit(HCI_CONN_ENCRYPT, &conn->flags);
if (!(hdev->commands[20] & 0x10)) {
conn->enc_key_size = HCI_LINK_KEY_SIZE;
} else {
cp.handle = cpu_to_le16(conn->handle);
if (hci_send_cmd(hdev, HCI_OP_READ_ENC_KEY_SIZE,
sizeof(cp), &cp)) {
bt_dev_err(hdev, "sending read key size failed");
conn->enc_key_size = HCI_LINK_KEY_SIZE;
}
}
hci_encrypt_cfm(conn, ev->status);
}
}
/* Get remote features */ /* Get remote features */
if (conn->type == ACL_LINK) { if (conn->type == ACL_LINK) {
struct hci_cp_read_remote_features cp; struct hci_cp_read_remote_features cp;
......
...@@ -617,7 +617,10 @@ void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err) ...@@ -617,7 +617,10 @@ void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err)
bt_dev_dbg(hdev, "err 0x%2.2x", err); bt_dev_dbg(hdev, "err 0x%2.2x", err);
if (hdev->req_status == HCI_REQ_PEND) { if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = err; /* req_result is __u32 so error must be positive to be properly
* propagated.
*/
hdev->req_result = err < 0 ? -err : err;
hdev->req_status = HCI_REQ_CANCELED; hdev->req_status = HCI_REQ_CANCELED;
wake_up_interruptible(&hdev->req_wait_q); wake_up_interruptible(&hdev->req_wait_q);
...@@ -3416,7 +3419,10 @@ static void hci_dev_get_bd_addr_from_property(struct hci_dev *hdev) ...@@ -3416,7 +3419,10 @@ static void hci_dev_get_bd_addr_from_property(struct hci_dev *hdev)
if (ret < 0 || !bacmp(&ba, BDADDR_ANY)) if (ret < 0 || !bacmp(&ba, BDADDR_ANY))
return; return;
bacpy(&hdev->public_addr, &ba); if (test_bit(HCI_QUIRK_BDADDR_PROPERTY_BROKEN, &hdev->quirks))
baswap(&hdev->public_addr, &ba);
else
bacpy(&hdev->public_addr, &ba);
} }
struct hci_init_stage { struct hci_init_stage {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment