diff options
| author | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2026-10-23 18:02:07 -0400 |
|---|---|---|
| committer | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2026-10-23 18:02:07 -0400 |
| commit | 47d4d9f67e92d56ef3965f2727f9c98a5a611368 (patch) | |
| tree | cb9d7d6c0b6ded07bfd713634d8f89d2da38b30e | |
| parent | d0ff9bf4eb339dbf5a940ddf280f3a3394ea3fac (diff) | |
| parent | 24a4c2f1f7cea608a3f8a94c023bb798093d1755 (diff) | |
| download | linux-next-47d4d9f67e92d56ef3965f2727f9c98a5a611368.tar.gz linux-next-47d4d9f67e92d56ef3965f2727f9c98a5a611368.zip | |
Merge branch 'bluetooth' into bluetooth-next
| -rw-r--r-- | drivers/bluetooth/btmtk.c | 44 | ||||
| -rw-r--r-- | drivers/bluetooth/btqca.c | 3 | ||||
| -rw-r--r-- | net/bluetooth/hci_sync.c | 74 | ||||
| -rw-r--r-- | net/bluetooth/mgmt.c | 2 |
4 files changed, 98 insertions, 25 deletions
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index a620e24b6c17..6a48ff0192cf 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -7,6 +7,7 @@ #include <linux/usb.h> #include <linux/iopoll.h> #include <linux/overflow.h> +#include <linux/string.h> #include <linux/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -30,7 +31,7 @@ #define BTMTK_CBMCU_FLAG_ENABLE_PATCH 0xF1 /* It is for mt79xx iso data transmission setting */ -#define MTK_ISO_THRESHOLD 264 +#define MTK_ISO_THRESHOLD 342 struct btmtk_patch_header { u8 datetime[16]; @@ -1550,8 +1551,15 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) struct btmtk_data *btmtk_data = hci_get_priv(hdev); struct sk_buff *skb; unsigned long flags; + unsigned int iso_mtu; int err = 0; + /* The controller reports the largest Data_Total_Length it will send in + * LE Read Buffer Size [v2]. Fall back to HCI_MAX_ISO_SIZE while that + * command has not completed yet. + */ + iso_mtu = hdev->iso_mtu ? hdev->iso_mtu : HCI_MAX_ISO_SIZE; + spin_lock_irqsave(&btmtk_data->isorxlock, flags); skb = btmtk_data->isopkt_skb; @@ -1559,7 +1567,16 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) int len; if (!skb) { - skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC); + /* Drop the endpoint's zero-filled padding before + * allocating an skb for it; a zero Data_Total_Length + * check below would miss a padding remainder + * shorter than an ISO header. + */ + if (mem_is_zero(buffer, count)) + break; + + skb = bt_skb_alloc(HCI_ISO_HDR_SIZE + iso_mtu, + GFP_ATOMIC); if (!skb) { err = -ENOMEM; break; @@ -1582,7 +1599,24 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) /* Complete ISO header */ hci_skb_expect(skb) = __le16_to_cpu(dlen); - if (skb_tailroom(skb) < hci_skb_expect(skb)) { + if (!hci_skb_expect(skb)) { + /* Zero padding was ruled out above, so a + * zero Data_Total_Length here is invalid. + */ + kfree_skb(skb); + skb = NULL; + + err = -EILSEQ; + break; + } + + /* Reject a length the controller said it would never + * send. The skb_tailroom() test is kept because a + * fragment started before hdev->iso_mtu was populated + * sits in a smaller skb than iso_mtu now allows. + */ + if (hci_skb_expect(skb) > iso_mtu || + skb_tailroom(skb) < hci_skb_expect(skb)) { kfree_skb(skb); skb = NULL; @@ -1701,7 +1735,7 @@ static int btmtk_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) static int btmtk_usb_isointf_init(struct hci_dev *hdev) { struct btmtk_data *btmtk_data = hci_get_priv(hdev); - u8 iso_param[2] = { 0x08, 0x01 }; + __le16 iso_param = cpu_to_le16(MTK_ISO_THRESHOLD); struct sk_buff *skb; int err; @@ -1716,7 +1750,7 @@ static int btmtk_usb_isointf_init(struct hci_dev *hdev) return err; } - skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), iso_param, + skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), &iso_param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb)); diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 22b08ab05b82..002307000d3c 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -426,7 +426,8 @@ static int qca_tlv_check_data(struct hci_dev *hdev, tlv_nvm->data[0] |= 0x80; /* UART Baud Rate */ - if (soc_type >= QCA_WCN3991) + if (soc_type == QCA_WCN3950 || + soc_type >= QCA_WCN3991) tlv_nvm->data[1] = nvm_baud_rate; else tlv_nvm->data[2] = nvm_baud_rate; diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index cb84a4288031..9d71ce96bd8e 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -2448,15 +2448,17 @@ static int hci_le_del_resolve_list_sync(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type) { struct hci_cp_le_del_from_resolv_list cp; - struct bdaddr_list_with_irk *entry; + bool exists; if (!ll_privacy_capable(hdev)) return 0; /* Check if the IRK has been programmed */ - entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, bdaddr, - bdaddr_type); - if (!entry) + hci_dev_lock(hdev); + exists = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, + bdaddr, bdaddr_type); + hci_dev_unlock(hdev); + if (!exists) return 0; cp.bdaddr_type = bdaddr_type; @@ -2512,8 +2514,8 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev, { struct hci_cp_le_add_to_resolv_list cp; struct smp_irk *irk; - struct bdaddr_list_with_irk *entry; struct hci_conn_params *p; + bool exists; if (!ll_privacy_capable(hdev)) return 0; @@ -2536,10 +2538,11 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev, return 0; /* Check if the IK has _not_ been programmed yet. */ - entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, - ¶ms->addr, - params->addr_type); - if (entry) + hci_dev_lock(hdev); + exists = hci_bdaddr_list_lookup_with_irk( + &hdev->le_resolv_list, ¶ms->addr, params->addr_type); + hci_dev_unlock(hdev); + if (exists) return 0; cp.bdaddr_type = params->addr_type; @@ -2885,6 +2888,31 @@ static struct conn_params *conn_params_copy(struct list_head *list, size_t *n) return p; } +static struct conn_params *le_accept_list_copy(struct hci_dev *hdev, + size_t *n) +{ + struct bdaddr_list *entry; + struct conn_params *params; + size_t i = 0; + + hci_dev_lock(hdev); + + *n = list_count_nodes(&hdev->le_accept_list); + params = kvzalloc_objs(struct conn_params, *n); + if (!params) + goto unlock; + + list_for_each_entry(entry, &hdev->le_accept_list, list) { + bacpy(¶ms[i].addr, &entry->bdaddr); + params[i].addr_type = entry->bdaddr_type; + i++; + } + +unlock: + hci_dev_unlock(hdev); + return params; +} + /* Clear LE Accept List */ static int hci_le_clear_accept_list_sync(struct hci_dev *hdev) { @@ -2915,7 +2943,6 @@ static int hci_le_clear_accept_list_sync(struct hci_dev *hdev) static u8 hci_update_accept_list_sync(struct hci_dev *hdev) { struct conn_params *params; - struct bdaddr_list *b, *t; u8 num_entries = 0; bool pend_conn, pend_report; u8 filter_policy; @@ -2980,20 +3007,27 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev) * report. If not present in either list, then remove it from * the controller. */ - list_for_each_entry_safe(b, t, &hdev->le_accept_list, list) { + params = le_accept_list_copy(hdev, &n); + if (!params) { + err = -ENOMEM; + goto done; + } + + for (i = 0; i < n; i++) { rcu_read_lock(); - if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type)) { + if (hci_conn_hash_lookup_le(hdev, ¶ms[i].addr, + params[i].addr_type)) { rcu_read_unlock(); continue; } pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns, - &b->bdaddr, - b->bdaddr_type); - pend_report = hci_pend_le_action_lookup(&hdev->pend_le_reports, - &b->bdaddr, - b->bdaddr_type); + ¶ms[i].addr, + params[i].addr_type); + pend_report = hci_pend_le_action_lookup( + &hdev->pend_le_reports, ¶ms[i].addr, + params[i].addr_type); rcu_read_unlock(); @@ -3001,14 +3035,16 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev) * remove it from the acceptlist. */ if (!pend_conn && !pend_report) { - hci_le_del_accept_list_sync(hdev, &b->bdaddr, - b->bdaddr_type); + hci_le_del_accept_list_sync(hdev, ¶ms[i].addr, + params[i].addr_type); continue; } num_entries++; } + kvfree(params); + /* Since all no longer valid accept list entries have been * removed, walk through the list of pending connections * and ensure that any new device gets programmed into diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 188c719c50ad..3cb4f9ece83c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -304,6 +304,8 @@ static u8 mgmt_errno_status(int err) return MGMT_STATUS_DISCONNECTED; case -ECANCELED: return MGMT_STATUS_CANCELLED; + case -ERFKILL: + return MGMT_STATUS_RFKILLED; } return MGMT_STATUS_FAILED; |
