Commit a54b2e2d authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Luiz Augusto von Dentz says:

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

 - btmtksdio: Check function enabled before doing close
 - btmtksdio: Do close if SDIO card removed without close
 - btusb: avoid NULL pointer dereference in skb_dequeue()
 - btintel_pcie: Avoid redundant buffer allocation
 - btintel_pcie: Add additional to checks to clear TX/RX paths
 - hci_conn: Fix not setting conn_timeout for Broadcast Receiver
 - hci_conn: Fix not setting timeout for BIG Create Sync

* tag 'for-net-2025-04-25' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: L2CAP: copy RX timestamp to new fragments
  Bluetooth: btintel_pcie: Add additional to checks to clear TX/RX paths
  Bluetooth: btmtksdio: Do close if SDIO card removed without close
  Bluetooth: btmtksdio: Check function enabled before doing close
  Bluetooth: btusb: avoid NULL pointer dereference in skb_dequeue()
  Bluetooth: btintel_pcie: Avoid redundant buffer allocation
  Bluetooth: hci_conn: Fix not setting timeout for BIG Create Sync
  Bluetooth: hci_conn: Fix not setting conn_timeout for Broadcast Receiver
====================

Link: https://patch.msgid.link/20250425192412.1578759-1-luiz.dentz@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 10c34b7d 3908feb1
Loading
Loading
Loading
Loading
+31 −26
Original line number Diff line number Diff line
@@ -957,9 +957,11 @@ static int btintel_pcie_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
		/* This is a debug event that comes from IML and OP image when it
		 * starts execution. There is no need pass this event to stack.
		 */
		if (skb->data[2] == 0x97)
		if (skb->data[2] == 0x97) {
			hci_recv_diag(hdev, skb);
			return 0;
		}
	}

	return hci_recv_frame(hdev, skb);
}
@@ -974,7 +976,6 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,
	u8 pkt_type;
	u16 plen;
	u32 pcie_pkt_type;
	struct sk_buff *new_skb;
	void *pdata;
	struct hci_dev *hdev = data->hdev;

@@ -1051,24 +1052,20 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,

	bt_dev_dbg(hdev, "pkt_type: 0x%2.2x len: %u", pkt_type, plen);

	new_skb = bt_skb_alloc(plen, GFP_ATOMIC);
	if (!new_skb) {
		bt_dev_err(hdev, "Failed to allocate memory for skb of len: %u",
			   skb->len);
		ret = -ENOMEM;
		goto exit_error;
	}

	hci_skb_pkt_type(new_skb) = pkt_type;
	skb_put_data(new_skb, skb->data, plen);
	hci_skb_pkt_type(skb) = pkt_type;
	hdev->stat.byte_rx += plen;
	skb_trim(skb, plen);

	if (pcie_pkt_type == BTINTEL_PCIE_HCI_EVT_PKT)
		ret = btintel_pcie_recv_event(hdev, new_skb);
		ret = btintel_pcie_recv_event(hdev, skb);
	else
		ret = hci_recv_frame(hdev, new_skb);
		ret = hci_recv_frame(hdev, skb);
	skb = NULL; /* skb is freed in the callee  */

exit_error:
	if (skb)
		kfree_skb(skb);

	if (ret)
		hdev->stat.err_rx++;

@@ -1202,8 +1199,6 @@ static void btintel_pcie_rx_work(struct work_struct *work)
	struct btintel_pcie_data *data = container_of(work,
					struct btintel_pcie_data, rx_work);
	struct sk_buff *skb;
	int err;
	struct hci_dev *hdev = data->hdev;

	if (test_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags)) {
		/* Unlike usb products, controller will not send hardware
@@ -1224,11 +1219,7 @@ static void btintel_pcie_rx_work(struct work_struct *work)

	/* Process the sk_buf in queue and send to the HCI layer */
	while ((skb = skb_dequeue(&data->rx_skb_q))) {
		err = btintel_pcie_recv_frame(data, skb);
		if (err)
			bt_dev_err(hdev, "Failed to send received frame: %d",
				   err);
		kfree_skb(skb);
		btintel_pcie_recv_frame(data, skb);
	}
}

@@ -1281,10 +1272,8 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data)
	bt_dev_dbg(hdev, "RXQ: cr_hia: %u  cr_tia: %u", cr_hia, cr_tia);

	/* Check CR_TIA and CR_HIA for change */
	if (cr_tia == cr_hia) {
		bt_dev_warn(hdev, "RXQ: no new CD found");
	if (cr_tia == cr_hia)
		return;
	}

	rxq = &data->rxq;

@@ -1320,6 +1309,16 @@ static irqreturn_t btintel_pcie_msix_isr(int irq, void *data)
	return IRQ_WAKE_THREAD;
}

static inline bool btintel_pcie_is_rxq_empty(struct btintel_pcie_data *data)
{
	return data->ia.cr_hia[BTINTEL_PCIE_RXQ_NUM] == data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM];
}

static inline bool btintel_pcie_is_txackq_empty(struct btintel_pcie_data *data)
{
	return data->ia.cr_tia[BTINTEL_PCIE_TXQ_NUM] == data->ia.cr_hia[BTINTEL_PCIE_TXQ_NUM];
}

static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
{
	struct msix_entry *entry = dev_id;
@@ -1351,12 +1350,18 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
		btintel_pcie_msix_gp0_handler(data);

	/* For TX */
	if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0)
	if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0) {
		btintel_pcie_msix_tx_handle(data);
		if (!btintel_pcie_is_rxq_empty(data))
			btintel_pcie_msix_rx_handle(data);
	}

	/* For RX */
	if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1)
	if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1) {
		btintel_pcie_msix_rx_handle(data);
		if (!btintel_pcie_is_txackq_empty(data))
			btintel_pcie_msix_tx_handle(data);
	}

	/*
	 * Before sending the interrupt the HW disables it to prevent a nested
+10 −2
Original line number Diff line number Diff line
@@ -723,6 +723,10 @@ static int btmtksdio_close(struct hci_dev *hdev)
{
	struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);

	/* Skip btmtksdio_close if BTMTKSDIO_FUNC_ENABLED isn't set */
	if (!test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
		return 0;

	sdio_claim_host(bdev->func);

	/* Disable interrupt */
@@ -1443,11 +1447,15 @@ static void btmtksdio_remove(struct sdio_func *func)
	if (!bdev)
		return;

	hdev = bdev->hdev;

	/* Make sure to call btmtksdio_close before removing sdio card */
	if (test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
		btmtksdio_close(hdev);

	/* Be consistent the state in btmtksdio_probe */
	pm_runtime_get_noresume(bdev->dev);

	hdev = bdev->hdev;

	sdio_set_drvdata(func, NULL);
	hci_unregister_dev(hdev);
	hci_free_dev(hdev);
+73 −28
Original line number Diff line number Diff line
@@ -3010,22 +3010,16 @@ static void btusb_coredump_qca(struct hci_dev *hdev)
		bt_dev_err(hdev, "%s: triggle crash failed (%d)", __func__, err);
}

/*
 * ==0: not a dump pkt.
 * < 0: fails to handle a dump pkt
 * > 0: otherwise.
 */
/* Return: 0 on success, negative errno on failure. */
static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
{
	int ret = 1;
	int ret = 0;
	u8 pkt_type;
	u8 *sk_ptr;
	unsigned int sk_len;
	u16 seqno;
	u32 dump_size;

	struct hci_event_hdr *event_hdr;
	struct hci_acl_hdr *acl_hdr;
	struct qca_dump_hdr *dump_hdr;
	struct btusb_data *btdata = hci_get_drvdata(hdev);
	struct usb_device *udev = btdata->udev;
@@ -3035,30 +3029,14 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
	sk_len = skb->len;

	if (pkt_type == HCI_ACLDATA_PKT) {
		acl_hdr = hci_acl_hdr(skb);
		if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)
			return 0;
		sk_ptr += HCI_ACL_HDR_SIZE;
		sk_len -= HCI_ACL_HDR_SIZE;
		event_hdr = (struct hci_event_hdr *)sk_ptr;
	} else {
		event_hdr = hci_event_hdr(skb);
	}

	if ((event_hdr->evt != HCI_VENDOR_PKT)
		|| (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
		return 0;

	sk_ptr += HCI_EVENT_HDR_SIZE;
	sk_len -= HCI_EVENT_HDR_SIZE;

	dump_hdr = (struct qca_dump_hdr *)sk_ptr;
	if ((sk_len < offsetof(struct qca_dump_hdr, data))
		|| (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS)
	    || (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
		return 0;

	/*it is dump pkt now*/
	seqno = le16_to_cpu(dump_hdr->seqno);
	if (seqno == 0) {
		set_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags);
@@ -3132,17 +3110,84 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
	return ret;
}

/* Return: true if the ACL packet is a dump packet, false otherwise. */
static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
{
	u8 *sk_ptr;
	unsigned int sk_len;

	struct hci_event_hdr *event_hdr;
	struct hci_acl_hdr *acl_hdr;
	struct qca_dump_hdr *dump_hdr;

	sk_ptr = skb->data;
	sk_len = skb->len;

	acl_hdr = hci_acl_hdr(skb);
	if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)
		return false;

	sk_ptr += HCI_ACL_HDR_SIZE;
	sk_len -= HCI_ACL_HDR_SIZE;
	event_hdr = (struct hci_event_hdr *)sk_ptr;

	if ((event_hdr->evt != HCI_VENDOR_PKT) ||
	    (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
		return false;

	sk_ptr += HCI_EVENT_HDR_SIZE;
	sk_len -= HCI_EVENT_HDR_SIZE;

	dump_hdr = (struct qca_dump_hdr *)sk_ptr;
	if ((sk_len < offsetof(struct qca_dump_hdr, data)) ||
	    (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) ||
	    (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
		return false;

	return true;
}

/* Return: true if the event packet is a dump packet, false otherwise. */
static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
{
	u8 *sk_ptr;
	unsigned int sk_len;

	struct hci_event_hdr *event_hdr;
	struct qca_dump_hdr *dump_hdr;

	sk_ptr = skb->data;
	sk_len = skb->len;

	event_hdr = hci_event_hdr(skb);

	if ((event_hdr->evt != HCI_VENDOR_PKT)
	    || (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
		return false;

	sk_ptr += HCI_EVENT_HDR_SIZE;
	sk_len -= HCI_EVENT_HDR_SIZE;

	dump_hdr = (struct qca_dump_hdr *)sk_ptr;
	if ((sk_len < offsetof(struct qca_dump_hdr, data)) ||
	    (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) ||
	    (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
		return false;

	return true;
}

static int btusb_recv_acl_qca(struct hci_dev *hdev, struct sk_buff *skb)
{
	if (handle_dump_pkt_qca(hdev, skb))
		return 0;
	if (acl_pkt_is_dump_qca(hdev, skb))
		return handle_dump_pkt_qca(hdev, skb);
	return hci_recv_frame(hdev, skb);
}

static int btusb_recv_evt_qca(struct hci_dev *hdev, struct sk_buff *skb)
{
	if (handle_dump_pkt_qca(hdev, skb))
		return 0;
	if (evt_pkt_is_dump_qca(hdev, skb))
		return handle_dump_pkt_qca(hdev, skb);
	return hci_recv_frame(hdev, skb);
}

+3 −1
Original line number Diff line number Diff line
@@ -1931,6 +1931,8 @@ struct hci_cp_le_pa_create_sync {
	__u8      sync_cte_type;
} __packed;

#define HCI_OP_LE_PA_CREATE_SYNC_CANCEL	0x2045

#define HCI_OP_LE_PA_TERM_SYNC		0x2046
struct hci_cp_le_pa_term_sync {
	__le16    handle;
@@ -2830,7 +2832,7 @@ struct hci_evt_le_create_big_complete {
	__le16  bis_handle[];
} __packed;

#define HCI_EVT_LE_BIG_SYNC_ESTABILISHED 0x1d
#define HCI_EVT_LE_BIG_SYNC_ESTABLISHED 0x1d
struct hci_evt_le_big_sync_estabilished {
	__u8    status;
	__u8    handle;
+9 −11
Original line number Diff line number Diff line
@@ -1113,10 +1113,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_bis(struct hci_dev *hdev,
	return NULL;
}

static inline struct hci_conn *hci_conn_hash_lookup_sid(struct hci_dev *hdev,
							__u8 sid,
							bdaddr_t *dst,
							__u8 dst_type)
static inline struct hci_conn *
hci_conn_hash_lookup_create_pa_sync(struct hci_dev *hdev)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	struct hci_conn  *c;
@@ -1124,8 +1122,10 @@ static inline struct hci_conn *hci_conn_hash_lookup_sid(struct hci_dev *hdev,
	rcu_read_lock();

	list_for_each_entry_rcu(c, &h->list, list) {
		if (c->type != ISO_LINK  || bacmp(&c->dst, dst) ||
		    c->dst_type != dst_type || c->sid != sid)
		if (c->type != ISO_LINK)
			continue;

		if (!test_bit(HCI_CONN_CREATE_PA_SYNC, &c->flags))
			continue;

		rcu_read_unlock();
@@ -1524,8 +1524,6 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle);
void hci_sco_setup(struct hci_conn *conn, __u8 status);
bool hci_iso_setup_path(struct hci_conn *conn);
int hci_le_create_cis_pending(struct hci_dev *hdev);
int hci_pa_create_sync_pending(struct hci_dev *hdev);
int hci_le_big_create_sync_pending(struct hci_dev *hdev);
int hci_conn_check_create_cis(struct hci_conn *conn);

struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
@@ -1566,9 +1564,9 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
				 __u8 data_len, __u8 *data);
struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
		       __u8 dst_type, __u8 sid, struct bt_iso_qos *qos);
int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
			   struct bt_iso_qos *qos,
			   __u16 sync_handle, __u8 num_bis, __u8 bis[]);
int hci_conn_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
			     struct bt_iso_qos *qos, __u16 sync_handle,
			     __u8 num_bis, __u8 bis[]);
int hci_conn_check_link_mode(struct hci_conn *conn);
int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level);
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type,
Loading