Skip to content

Commit

Permalink
Merge tag 'for-net-2023-03-23' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/bluetooth/bluetooth

Luiz Augusto von Dentz says:

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

 - Fix MGMT add advmon with RSSI command
 - L2CAP: Fix responding with wrong PDU type
 - Fix race condition in hci_cmd_sync_clear
 - ISO: Fix timestamped HCI ISO data packet parsing
 - HCI: Fix global-out-of-bounds
 - hci_sync: Resume adv with no RPA when active scan

* tag 'for-net-2023-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: HCI: Fix global-out-of-bounds
  Bluetooth: mgmt: Fix MGMT add advmon with RSSI command
  Bluetooth: btsdio: fix use after free bug in btsdio_remove due to unfinished work
  Bluetooth: L2CAP: Fix responding with wrong PDU type
  Bluetooth: btqcomsmd: Fix command timeout after setting BD address
  Bluetooth: btinel: Check ACPI handle for NULL before accessing
  Bluetooth: Remove "Power-on" check from Mesh feature
  Bluetooth: Fix race condition in hci_cmd_sync_clear
  Bluetooth: btintel: Iterate only bluetooth device ACPI entries
  Bluetooth: ISO: fix timestamped HCI ISO data packet parsing
  Bluetooth: btusb: Remove detection of ISO packets over bulk
  Bluetooth: hci_core: Detect if an ACL packet is in fact an ISO packet
  Bluetooth: hci_sync: Resume adv with no RPA when active scan
====================

Link: https://lore.kernel.org/r/20230323202335.3380841-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Mar 23, 2023
2 parents 4f44d32 + bce5640 commit 2e63a2d
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 107 deletions.
51 changes: 33 additions & 18 deletions drivers/bluetooth/btintel.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@
#define ECDSA_HEADER_LEN 320

#define BTINTEL_PPAG_NAME "PPAG"
#define BTINTEL_PPAG_PREFIX "\\_SB_.PCI0.XHCI.RHUB"

/* structure to store the PPAG data read from ACPI table */
struct btintel_ppag {
u32 domain;
u32 mode;
acpi_status status;
struct hci_dev *hdev;
};

#define CMD_WRITE_BOOT_PARAMS 0xfc0e
struct cmd_write_boot_params {
Expand Down Expand Up @@ -1295,17 +1302,16 @@ static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data

status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
if (ACPI_FAILURE(status)) {
bt_dev_warn(hdev, "ACPI Failure: %s", acpi_format_exception(status));
bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
return status;
}

if (strncmp(BTINTEL_PPAG_PREFIX, string.pointer,
strlen(BTINTEL_PPAG_PREFIX))) {
len = strlen(string.pointer);
if (len < strlen(BTINTEL_PPAG_NAME)) {
kfree(string.pointer);
return AE_OK;
}

len = strlen(string.pointer);
if (strncmp((char *)string.pointer + len - 4, BTINTEL_PPAG_NAME, 4)) {
kfree(string.pointer);
return AE_OK;
Expand All @@ -1314,7 +1320,8 @@ static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data

status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
if (ACPI_FAILURE(status)) {
bt_dev_warn(hdev, "ACPI Failure: %s", acpi_format_exception(status));
ppag->status = status;
bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
return status;
}

Expand All @@ -1323,8 +1330,9 @@ static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data

if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 2) {
kfree(buffer.pointer);
bt_dev_warn(hdev, "Invalid object type: %d or package count: %d",
bt_dev_warn(hdev, "PPAG-BT: Invalid object type: %d or package count: %d",
p->type, p->package.count);
ppag->status = AE_ERROR;
return AE_ERROR;
}

Expand All @@ -1335,6 +1343,7 @@ static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data

ppag->domain = (u32)p->package.elements[0].integer.value;
ppag->mode = (u32)p->package.elements[1].integer.value;
ppag->status = AE_OK;
kfree(buffer.pointer);
return AE_CTRL_TERMINATE;
}
Expand Down Expand Up @@ -2314,42 +2323,48 @@ static int btintel_configure_offload(struct hci_dev *hdev)

static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver)
{
acpi_status status;
struct btintel_ppag ppag;
struct sk_buff *skb;
struct btintel_loc_aware_reg ppag_cmd;
acpi_handle handle;

/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
switch (ver->cnvr_top & 0xFFF) {
case 0x504: /* Hrp2 */
case 0x202: /* Jfp2 */
case 0x201: /* Jfp1 */
return;
}

handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
if (!handle) {
bt_dev_info(hdev, "No support for BT device in ACPI firmware");
return;
}

memset(&ppag, 0, sizeof(ppag));

ppag.hdev = hdev;
status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, NULL,
btintel_ppag_callback, &ppag, NULL);
ppag.status = AE_NOT_FOUND;
acpi_walk_namespace(ACPI_TYPE_PACKAGE, handle, 1, NULL,
btintel_ppag_callback, &ppag, NULL);

if (ACPI_FAILURE(status)) {
/* Do not log warning message if ACPI entry is not found */
if (status == AE_NOT_FOUND)
if (ACPI_FAILURE(ppag.status)) {
if (ppag.status == AE_NOT_FOUND) {
bt_dev_dbg(hdev, "PPAG-BT: ACPI entry not found");
return;
bt_dev_warn(hdev, "PPAG: ACPI Failure: %s", acpi_format_exception(status));
}
return;
}

if (ppag.domain != 0x12) {
bt_dev_warn(hdev, "PPAG-BT Domain disabled");
bt_dev_warn(hdev, "PPAG-BT: domain is not bluetooth");
return;
}

/* PPAG mode, BIT0 = 0 Disabled, BIT0 = 1 Enabled */
if (!(ppag.mode & BIT(0))) {
bt_dev_dbg(hdev, "PPAG disabled");
bt_dev_dbg(hdev, "PPAG-BT: disabled");
return;
}

Expand Down
7 changes: 0 additions & 7 deletions drivers/bluetooth/btintel.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,6 @@ struct intel_offload_use_cases {
__u8 preset[8];
} __packed;

/* structure to store the PPAG data read from ACPI table */
struct btintel_ppag {
u32 domain;
u32 mode;
struct hci_dev *hdev;
};

struct btintel_loc_aware_reg {
__le32 mcc;
__le32 sel;
Expand Down
17 changes: 16 additions & 1 deletion drivers/bluetooth/btqcomsmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,21 @@ static int btqcomsmd_setup(struct hci_dev *hdev)
return 0;
}

static int btqcomsmd_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{
int ret;

ret = qca_set_bdaddr_rome(hdev, bdaddr);
if (ret)
return ret;

/* The firmware stops responding for a while after setting the bdaddr,
* causing timeouts for subsequent commands. Sleep a bit to avoid this.
*/
usleep_range(1000, 10000);
return 0;
}

static int btqcomsmd_probe(struct platform_device *pdev)
{
struct btqcomsmd *btq;
Expand Down Expand Up @@ -162,7 +177,7 @@ static int btqcomsmd_probe(struct platform_device *pdev)
hdev->close = btqcomsmd_close;
hdev->send = btqcomsmd_send;
hdev->setup = btqcomsmd_setup;
hdev->set_bdaddr = qca_set_bdaddr_rome;
hdev->set_bdaddr = btqcomsmd_set_bdaddr;

ret = hci_register_dev(hdev);
if (ret < 0)
Expand Down
1 change: 1 addition & 0 deletions drivers/bluetooth/btsdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ static void btsdio_remove(struct sdio_func *func)

BT_DBG("func %p", func);

cancel_work_sync(&data->work);
if (!data)
return;

Expand Down
10 changes: 0 additions & 10 deletions drivers/bluetooth/btusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1050,21 +1050,11 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
hci_skb_expect(skb) -= len;

if (skb->len == HCI_ACL_HDR_SIZE) {
__u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
__le16 dlen = hci_acl_hdr(skb)->dlen;
__u8 type;

/* Complete ACL header */
hci_skb_expect(skb) = __le16_to_cpu(dlen);

/* Detect if ISO packet has been sent over bulk */
if (hci_conn_num(data->hdev, ISO_LINK)) {
type = hci_conn_lookup_type(data->hdev,
hci_handle(handle));
if (type == ISO_LINK)
hci_skb_pkt_type(skb) = HCI_ISODATA_PKT;
}

if (skb_tailroom(skb) < hci_skb_expect(skb)) {
kfree_skb(skb);
skb = NULL;
Expand Down
1 change: 1 addition & 0 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,7 @@ void hci_conn_add_sysfs(struct hci_conn *conn);
void hci_conn_del_sysfs(struct hci_conn *conn);

#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))
#define GET_HCIDEV_DEV(hdev) ((hdev)->dev.parent)

/* ----- LMP capabilities ----- */
#define lmp_encrypt_capable(dev) ((dev)->features[0][0] & LMP_ENCRYPT)
Expand Down
23 changes: 19 additions & 4 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2871,10 +2871,25 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
return -ENXIO;
}

if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT &&
hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
hci_skb_pkt_type(skb) != HCI_SCODATA_PKT &&
hci_skb_pkt_type(skb) != HCI_ISODATA_PKT) {
switch (hci_skb_pkt_type(skb)) {
case HCI_EVENT_PKT:
break;
case HCI_ACLDATA_PKT:
/* Detect if ISO packet has been sent as ACL */
if (hci_conn_num(hdev, ISO_LINK)) {
__u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
__u8 type;

type = hci_conn_lookup_type(hdev, hci_handle(handle));
if (type == ISO_LINK)
hci_skb_pkt_type(skb) = HCI_ISODATA_PKT;
}
break;
case HCI_SCODATA_PKT:
break;
case HCI_ISODATA_PKT:
break;
default:
kfree_skb(skb);
return -EINVAL;
}
Expand Down
68 changes: 48 additions & 20 deletions net/bluetooth/hci_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,13 +643,15 @@ void hci_cmd_sync_clear(struct hci_dev *hdev)
cancel_work_sync(&hdev->cmd_sync_work);
cancel_work_sync(&hdev->reenable_adv_work);

mutex_lock(&hdev->cmd_sync_work_lock);
list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) {
if (entry->destroy)
entry->destroy(hdev, entry->data, -ECANCELED);

list_del(&entry->list);
kfree(entry);
}
mutex_unlock(&hdev->cmd_sync_work_lock);
}

void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
Expand Down Expand Up @@ -2367,6 +2369,45 @@ static int hci_resume_advertising_sync(struct hci_dev *hdev)
return err;
}

static int hci_pause_addr_resolution(struct hci_dev *hdev)
{
int err;

if (!use_ll_privacy(hdev))
return 0;

if (!hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
return 0;

/* Cannot disable addr resolution if scanning is enabled or
* when initiating an LE connection.
*/
if (hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
hci_lookup_le_connect(hdev)) {
bt_dev_err(hdev, "Command not allowed when scan/LE connect");
return -EPERM;
}

/* Cannot disable addr resolution if advertising is enabled. */
err = hci_pause_advertising_sync(hdev);
if (err) {
bt_dev_err(hdev, "Pause advertising failed: %d", err);
return err;
}

err = hci_le_set_addr_resolution_enable_sync(hdev, 0x00);
if (err)
bt_dev_err(hdev, "Unable to disable Address Resolution: %d",
err);

/* Return if address resolution is disabled and RPA is not used. */
if (!err && scan_use_rpa(hdev))
return err;

hci_resume_advertising_sync(hdev);
return err;
}

struct sk_buff *hci_read_local_oob_data_sync(struct hci_dev *hdev,
bool extended, struct sock *sk)
{
Expand Down Expand Up @@ -2402,7 +2443,7 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
u8 filter_policy;
int err;

/* Pause advertising if resolving list can be used as controllers are
/* Pause advertising if resolving list can be used as controllers
* cannot accept resolving list modifications while advertising.
*/
if (use_ll_privacy(hdev)) {
Expand Down Expand Up @@ -3319,6 +3360,7 @@ static const struct hci_init_stage amp_init1[] = {
HCI_INIT(hci_read_flow_control_mode_sync),
/* HCI_OP_READ_LOCATION_DATA */
HCI_INIT(hci_read_location_data_sync),
{}
};

static int hci_init1_sync(struct hci_dev *hdev)
Expand Down Expand Up @@ -3353,6 +3395,7 @@ static int hci_init1_sync(struct hci_dev *hdev)
static const struct hci_init_stage amp_init2[] = {
/* HCI_OP_READ_LOCAL_FEATURES */
HCI_INIT(hci_read_local_features_sync),
{}
};

/* Read Buffer Size (ACL mtu, max pkt, etc.) */
Expand Down Expand Up @@ -5394,27 +5437,12 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval)

cancel_interleave_scan(hdev);

/* Pause advertising since active scanning disables address resolution
* which advertising depend on in order to generate its RPAs.
*/
if (use_ll_privacy(hdev) && hci_dev_test_flag(hdev, HCI_PRIVACY)) {
err = hci_pause_advertising_sync(hdev);
if (err) {
bt_dev_err(hdev, "pause advertising failed: %d", err);
goto failed;
}
}

/* Disable address resolution while doing active scanning since the
* accept list shall not be used and all reports shall reach the host
* anyway.
/* Pause address resolution for active scan and stop advertising if
* privacy is enabled.
*/
err = hci_le_set_addr_resolution_enable_sync(hdev, 0x00);
if (err) {
bt_dev_err(hdev, "Unable to disable Address Resolution: %d",
err);
err = hci_pause_addr_resolution(hdev);
if (err)
goto failed;
}

/* All active scans will be done with either a resolvable private
* address (when privacy feature has been enabled) or non-resolvable
Expand Down
9 changes: 7 additions & 2 deletions net/bluetooth/iso.c
Original file line number Diff line number Diff line change
Expand Up @@ -1620,7 +1620,6 @@ static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason)
void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
{
struct iso_conn *conn = hcon->iso_data;
struct hci_iso_data_hdr *hdr;
__u16 pb, ts, len;

if (!conn)
Expand All @@ -1642,22 +1641,28 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
}

if (ts) {
struct hci_iso_ts_data_hdr *hdr;

/* TODO: add timestamp to the packet? */
hdr = skb_pull_data(skb, HCI_ISO_TS_DATA_HDR_SIZE);
if (!hdr) {
BT_ERR("Frame is too short (len %d)", skb->len);
goto drop;
}

len = __le16_to_cpu(hdr->slen);
} else {
struct hci_iso_data_hdr *hdr;

hdr = skb_pull_data(skb, HCI_ISO_DATA_HDR_SIZE);
if (!hdr) {
BT_ERR("Frame is too short (len %d)", skb->len);
goto drop;
}

len = __le16_to_cpu(hdr->slen);
}

len = __le16_to_cpu(hdr->slen);
flags = hci_iso_data_flags(len);
len = hci_iso_data_len(len);

Expand Down
Loading

0 comments on commit 2e63a2d

Please sign in to comment.