summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2026-10-23 18:02:07 -0400
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2026-10-23 18:02:07 -0400
commit47d4d9f67e92d56ef3965f2727f9c98a5a611368 (patch)
treecb9d7d6c0b6ded07bfd713634d8f89d2da38b30e
parentd0ff9bf4eb339dbf5a940ddf280f3a3394ea3fac (diff)
parent24a4c2f1f7cea608a3f8a94c023bb798093d1755 (diff)
downloadlinux-next-47d4d9f67e92d56ef3965f2727f9c98a5a611368.tar.gz
linux-next-47d4d9f67e92d56ef3965f2727f9c98a5a611368.zip
Merge branch 'bluetooth' into bluetooth-next
-rw-r--r--drivers/bluetooth/btmtk.c44
-rw-r--r--drivers/bluetooth/btqca.c3
-rw-r--r--net/bluetooth/hci_sync.c74
-rw-r--r--net/bluetooth/mgmt.c2
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,
- &params->addr,
- params->addr_type);
- if (entry)
+ hci_dev_lock(hdev);
+ exists = hci_bdaddr_list_lookup_with_irk(
+ &hdev->le_resolv_list, &params->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(&params[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, &params[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);
+ &params[i].addr,
+ params[i].addr_type);
+ pend_report = hci_pend_le_action_lookup(
+ &hdev->pend_le_reports, &params[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, &params[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;