--- /dev/null
+From stable+bounces-275100-greg=kroah.com@vger.kernel.org Thu Jul 16 01:55:45 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jul 2026 19:55:29 -0400
+Subject: Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()
+To: stable@vger.kernel.org
+Cc: Siwei Zhang <oss@fourdim.xyz>, XIAO WU <xiaowu.417@qq.com>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260715235529.525959-4-sashal@kernel.org>
+
+From: Siwei Zhang <oss@fourdim.xyz>
+
+[ Upstream commit 12917f591cea1af36087dba5b9ec888652f0b42a ]
+
+hci_abort_conn() read hci_skb_event(hdev->sent_cmd) when a connection
+was pending, but hdev->sent_cmd can be NULL while req_status is still
+HCI_REQ_PEND, leading to a NULL pointer dereference and a general
+protection fault from the hci_rx_work() receive path.
+
+Instead of inspecting hdev->sent_cmd, track the in-flight create
+connection command with a new per-connection HCI_CONN_CREATE flag and
+route all cancellation through hci_cancel_connect_sync(), which
+dispatches to a dedicated per-type cancel function. The create command
+is in exactly one of two states: still queued, or in flight. The cancel
+function holds cmd_sync_work_lock across the whole decision: the worker
+takes this lock to dequeue every entry, so while it is held a queued
+command cannot start running and an in-flight command cannot complete
+and let the next command become pending. This keeps the flag test and
+hci_cmd_sync_cancel() atomic with respect to the worker, so a queued
+command is simply dequeued, and an in-flight command owned by this
+connection is cancelled without the risk of cancelling an unrelated
+command that became pending in the meantime. CIS uses the same flag
+mechanism via HCI_CONN_CREATE_CIS but cannot be dequeued per-connection.
+
+hci_acl_create_conn_sync() and hci_le_create_conn_sync() clear
+HCI_CONN_CREATE after the create command completes, but the command
+status handler can free conn via hci_conn_del() (for example when the
+controller rejects the connection) while the worker is still blocked on
+the connection complete event. Hold a reference on conn across the
+create command so the flag can be cleared without a use-after-free.
+
+Fixes: a13f316e90fd ("Bluetooth: hci_conn: Consolidate code for aborting connections")
+Cc: stable@vger.kernel.org
+Suggested-by: XIAO WU <xiaowu.417@qq.com>
+Assisted-by: Claude:claude-opus-4-8
+Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/bluetooth/hci_core.h | 1
+ net/bluetooth/hci_conn.c | 21 ------
+ net/bluetooth/hci_sync.c | 133 ++++++++++++++++++++++++++++++++++-----
+ 3 files changed, 123 insertions(+), 32 deletions(-)
+
+--- a/include/net/bluetooth/hci_core.h
++++ b/include/net/bluetooth/hci_core.h
+@@ -957,6 +957,7 @@ enum {
+ HCI_CONN_AUTH_FAILURE,
+ HCI_CONN_PER_ADV,
+ HCI_CONN_BIG_CREATED,
++ HCI_CONN_CREATE,
+ HCI_CONN_CREATE_CIS,
+ HCI_CONN_BIG_SYNC,
+ HCI_CONN_BIG_SYNC_FAILED,
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -2910,26 +2910,11 @@ int hci_abort_conn(struct hci_conn *conn
+
+ conn->abort_reason = reason;
+
+- /* If the connection is pending check the command opcode since that
+- * might be blocking on hci_cmd_sync_work while waiting its respective
+- * event so we need to hci_cmd_sync_cancel to cancel it.
+- *
+- * hci_connect_le serializes the connection attempts so only one
+- * connection can be in BT_CONNECT at time.
++ /* Cancel the connect attempt. A return of 0 means the create command
++ * was still queued and got dequeued, so there is nothing to disconnect.
+ */
+- if (conn->state == BT_CONNECT && READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
+- switch (hci_skb_event(hdev->sent_cmd)) {
+- case HCI_EV_CONN_COMPLETE:
+- case HCI_EV_LE_CONN_COMPLETE:
+- case HCI_EV_LE_ENHANCED_CONN_COMPLETE:
+- case HCI_EVT_LE_CIS_ESTABLISHED:
+- hci_cmd_sync_cancel(hdev, ECANCELED);
+- break;
+- }
+- /* Cancel connect attempt if still queued/pending */
+- } else if (!hci_cancel_connect_sync(hdev, conn)) {
++ if (!hci_cancel_connect_sync(hdev, conn))
+ return 0;
+- }
+
+ /* Run immediately if on cmd_sync_work since this may be called
+ * as a result to MGMT_OP_DISCONNECT/MGMT_OP_UNPAIR which does
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -6557,6 +6557,11 @@ static int hci_le_create_conn_sync(struc
+
+ bt_dev_dbg(hdev, "conn %p", conn);
+
++ /* Hold a reference so conn stays valid for the HCI_CONN_CREATE
++ * clear_bit() at done.
++ */
++ hci_conn_get(conn);
++
+ clear_bit(HCI_CONN_SCANNING, &conn->flags);
+ conn->state = BT_CONNECT;
+
+@@ -6569,6 +6574,7 @@ static int hci_le_create_conn_sync(struc
+ hdev->le_scan_type == LE_SCAN_ACTIVE &&
+ !hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES)) {
+ hci_conn_del(conn);
++ hci_conn_put(conn);
+ return -EBUSY;
+ }
+
+@@ -6614,6 +6620,12 @@ static int hci_le_create_conn_sync(struc
+ &own_addr_type);
+ if (err)
+ goto done;
++
++ /* Mark create connection in flight so hci_cancel_connect_sync() can
++ * cancel it while blocking on the connection complete event.
++ */
++ set_bit(HCI_CONN_CREATE, &conn->flags);
++
+ /* Send command LE Extended Create Connection if supported */
+ if (use_ext_conn(hdev)) {
+ err = hci_le_ext_create_conn_sync(hdev, conn, own_addr_type);
+@@ -6649,11 +6661,14 @@ static int hci_le_create_conn_sync(struc
+ conn->conn_timeout, NULL);
+
+ done:
++ clear_bit(HCI_CONN_CREATE, &conn->flags);
++
+ if (err == -ETIMEDOUT)
+ hci_le_connect_cancel_sync(hdev, conn, 0x00);
+
+ /* Re-enable advertising after the connection attempt is finished. */
+ hci_resume_advertising_sync(hdev);
++ hci_conn_put(conn);
+ return err;
+ }
+
+@@ -6932,10 +6947,25 @@ static int hci_acl_create_conn_sync(stru
+ else
+ cp.role_switch = 0x00;
+
+- return __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN,
+- sizeof(cp), &cp,
+- HCI_EV_CONN_COMPLETE,
+- conn->conn_timeout, NULL);
++ /* Hold a reference so conn stays valid for the HCI_CONN_CREATE
++ * clear_bit() below.
++ */
++ hci_conn_get(conn);
++
++ /* Mark create connection in flight so hci_cancel_connect_sync() can
++ * cancel it while blocking on the connection complete event.
++ */
++ set_bit(HCI_CONN_CREATE, &conn->flags);
++
++ err = __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN,
++ sizeof(cp), &cp,
++ HCI_EV_CONN_COMPLETE,
++ conn->conn_timeout, NULL);
++
++ clear_bit(HCI_CONN_CREATE, &conn->flags);
++ hci_conn_put(conn);
++
++ return err;
+ }
+
+ int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
+@@ -6981,20 +7011,95 @@ int hci_connect_le_sync(struct hci_dev *
+ create_le_conn_complete);
+ }
+
+-int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn)
++static int hci_acl_cancel_create_conn_sync(struct hci_dev *hdev,
++ struct hci_conn *conn)
++{
++ struct hci_cmd_sync_work_entry *entry;
++ int err = -EBUSY;
++
++ /* cmd_sync_work_lock makes the HCI_CONN_CREATE test and the cancel
++ * atomic against the worker, which takes this lock to dequeue every
++ * entry: while it is held no other command can become pending, so
++ * hci_cmd_sync_cancel() cannot cancel an unrelated command.
++ */
++ mutex_lock(&hdev->cmd_sync_work_lock);
++
++ /* In flight: this connection owns the pending request, cancel it. */
++ if (test_bit(HCI_CONN_CREATE, &conn->flags)) {
++ hci_cmd_sync_cancel(hdev, ECANCELED);
++ goto unlock;
++ }
++
++ /* Still queued: a successful dequeue means it never started, so there
++ * is nothing to disconnect.
++ */
++ entry = _hci_cmd_sync_lookup_entry(hdev, hci_acl_create_conn_sync, conn,
++ NULL);
++ if (entry) {
++ _hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
++ err = 0;
++ }
++
++unlock:
++ mutex_unlock(&hdev->cmd_sync_work_lock);
++ return err;
++}
++
++static int hci_le_cancel_create_conn_sync(struct hci_dev *hdev,
++ struct hci_conn *conn)
+ {
+- if (conn->state != BT_OPEN)
+- return -EINVAL;
++ struct hci_cmd_sync_work_entry *entry;
++ int err = -EBUSY;
++
++ /* cmd_sync_work_lock keeps the HCI_CONN_CREATE test and the cancel
++ * atomic against the cmd_sync worker.
++ */
++ mutex_lock(&hdev->cmd_sync_work_lock);
++
++ if (test_bit(HCI_CONN_CREATE, &conn->flags)) {
++ hci_cmd_sync_cancel(hdev, ECANCELED);
++ goto unlock;
++ }
+
++ entry = _hci_cmd_sync_lookup_entry(hdev, hci_le_create_conn_sync, conn,
++ create_le_conn_complete);
++ if (entry) {
++ _hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
++ err = 0;
++ }
++
++unlock:
++ mutex_unlock(&hdev->cmd_sync_work_lock);
++ return err;
++}
++
++static int hci_cis_cancel_create_conn_sync(struct hci_dev *hdev,
++ struct hci_conn *conn)
++{
++ /* LE Create CIS is shared by the whole CIG and cannot be dequeued
++ * per-connection, so only an in-flight command can be cancelled.
++ * cmd_sync_work_lock keeps the test and the cancel atomic against the
++ * cmd_sync worker.
++ */
++ mutex_lock(&hdev->cmd_sync_work_lock);
++
++ if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags))
++ hci_cmd_sync_cancel(hdev, ECANCELED);
++
++ mutex_unlock(&hdev->cmd_sync_work_lock);
++ return -EBUSY;
++}
++
++int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn)
++{
+ switch (conn->type) {
+ case ACL_LINK:
+- return !hci_cmd_sync_dequeue_once(hdev,
+- hci_acl_create_conn_sync,
+- conn, NULL);
++ return hci_acl_cancel_create_conn_sync(hdev, conn);
+ case LE_LINK:
+- return !hci_cmd_sync_dequeue_once(hdev, hci_le_create_conn_sync,
+- conn, create_le_conn_complete);
++ return hci_le_cancel_create_conn_sync(hdev, conn);
++ case CIS_LINK:
++ return hci_cis_cancel_create_conn_sync(hdev, conn);
++ default:
++ return -ENOENT;
+ }
+-
+- return -ENOENT;
+ }
--- /dev/null
+From stable+bounces-275097-greg=kroah.com@vger.kernel.org Thu Jul 16 01:55:36 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jul 2026 19:55:26 -0400
+Subject: Bluetooth: hci_core: Enable buffer flow control for SCO/eSCO
+To: stable@vger.kernel.org
+Cc: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Pauli Virtanen <pav@iki.fi>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260715235529.525959-1-sashal@kernel.org>
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ Upstream commit 13218453521d75916dfed55efb8e809bfc03cb4b ]
+
+This enables buffer flow control for SCO/eSCO
+(see: Bluetooth Core 6.0 spec: 6.22. Synchronous Flow Control Enable),
+recently this has caused the following problem and is actually a nice
+addition for the likes of Socket TX complete:
+
+< HCI Command: Read Buffer Size (0x04|0x0005) plen 0
+> HCI Event: Command Complete (0x0e) plen 11
+ Read Buffer Size (0x04|0x0005) ncmd 1
+ Status: Success (0x00)
+ ACL MTU: 1021 ACL max packet: 5
+ SCO MTU: 240 SCO max packet: 8
+...
+< SCO Data TX: Handle 257 flags 0x00 dlen 120
+< SCO Data TX: Handle 257 flags 0x00 dlen 120
+< SCO Data TX: Handle 257 flags 0x00 dlen 120
+< SCO Data TX: Handle 257 flags 0x00 dlen 120
+< SCO Data TX: Handle 257 flags 0x00 dlen 120
+< SCO Data TX: Handle 257 flags 0x00 dlen 120
+< SCO Data TX: Handle 257 flags 0x00 dlen 120
+< SCO Data TX: Handle 257 flags 0x00 dlen 120
+< SCO Data TX: Handle 257 flags 0x00 dlen 120
+> HCI Event: Hardware Error (0x10) plen 1
+ Code: 0x0a
+
+To fix the code will now attempt to enable buffer flow control when
+HCI_QUIRK_SYNC_FLOWCTL_SUPPORTED is set by the driver:
+
+< HCI Command: Write Sync Fl.. (0x03|0x002f) plen 1
+ Flow control: Enabled (0x01)
+> HCI Event: Command Complete (0x0e) plen 4
+ Write Sync Flow Control Enable (0x03|0x002f) ncmd 1
+ Status: Success (0x00)
+
+On success then HCI_SCO_FLOWCTL would be set which indicates sco_cnt
+shall be used for flow contro.
+
+Fixes: 7fedd3bb6b77 ("Bluetooth: Prioritize SCO traffic")
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Tested-by: Pauli Virtanen <pav@iki.fi>
+Stable-dep-of: 12917f591cea ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/bluetooth/hci.h | 13 ++++++++
+ include/net/bluetooth/hci_core.h | 1
+ net/bluetooth/hci_core.c | 62 +++++++++++++++++----------------------
+ net/bluetooth/hci_event.c | 2 +
+ net/bluetooth/hci_sync.c | 24 +++++++++++++++
+ 5 files changed, 68 insertions(+), 34 deletions(-)
+
+--- a/include/net/bluetooth/hci.h
++++ b/include/net/bluetooth/hci.h
+@@ -206,6 +206,13 @@ enum {
+ */
+ HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
+
++ /* When this quirk is set consider Sync Flow Control as supported by
++ * the driver.
++ *
++ * This quirk must be set before hci_register_dev is called.
++ */
++ HCI_QUIRK_SYNC_FLOWCTL_SUPPORTED,
++
+ /* When this quirk is set, the controller has validated that
+ * LE states reported through the HCI_LE_READ_SUPPORTED_STATES are
+ * valid. This mechanism is necessary as many controllers have
+@@ -416,6 +423,7 @@ enum {
+ HCI_WIDEBAND_SPEECH_ENABLED,
+ HCI_EVENT_FILTER_CONFIGURED,
+ HCI_PA_SYNC,
++ HCI_SCO_FLOWCTL,
+
+ HCI_DUT_MODE,
+ HCI_VENDOR_DIAG,
+@@ -1513,6 +1521,11 @@ struct hci_rp_read_tx_power {
+ __s8 tx_power;
+ } __packed;
+
++#define HCI_OP_WRITE_SYNC_FLOWCTL 0x0c2f
++struct hci_cp_write_sync_flowctl {
++ __u8 enable;
++} __packed;
++
+ #define HCI_OP_READ_PAGE_SCAN_TYPE 0x0c46
+ struct hci_rp_read_page_scan_type {
+ __u8 status;
+--- a/include/net/bluetooth/hci_core.h
++++ b/include/net/bluetooth/hci_core.h
+@@ -1824,6 +1824,7 @@ void hci_conn_del_sysfs(struct hci_conn
+ #define lmp_hold_capable(dev) ((dev)->features[0][0] & LMP_HOLD)
+ #define lmp_sniff_capable(dev) ((dev)->features[0][0] & LMP_SNIFF)
+ #define lmp_park_capable(dev) ((dev)->features[0][1] & LMP_PARK)
++#define lmp_sco_capable(dev) ((dev)->features[0][1] & LMP_SCO)
+ #define lmp_inq_rssi_capable(dev) ((dev)->features[0][3] & LMP_RSSI_INQ)
+ #define lmp_esco_capable(dev) ((dev)->features[0][3] & LMP_ESCO)
+ #define lmp_bredr_capable(dev) (!((dev)->features[0][4] & LMP_NO_BREDR))
+--- a/net/bluetooth/hci_core.c
++++ b/net/bluetooth/hci_core.c
+@@ -3556,42 +3556,27 @@ static void __check_timeout(struct hci_d
+ }
+
+ /* Schedule SCO */
+-static void hci_sched_sco(struct hci_dev *hdev)
++static void hci_sched_sco(struct hci_dev *hdev, __u8 type)
+ {
+ struct hci_conn *conn;
+ struct sk_buff *skb;
+- int quote;
++ int quote, *cnt;
++ unsigned int pkts = hdev->sco_pkts;
+
+- BT_DBG("%s", hdev->name);
++ bt_dev_dbg(hdev, "type %u", type);
+
+- if (!hci_conn_num(hdev, SCO_LINK))
++ if (!hci_conn_num(hdev, type) || !pkts)
+ return;
+
+- while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, "e))) {
+- while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+- BT_DBG("skb %p len %d", skb, skb->len);
+- hci_send_frame(hdev, skb);
+-
+- conn->sent++;
+- if (conn->sent == ~0)
+- conn->sent = 0;
+- }
+- }
+-}
+-
+-static void hci_sched_esco(struct hci_dev *hdev)
+-{
+- struct hci_conn *conn;
+- struct sk_buff *skb;
+- int quote;
+-
+- BT_DBG("%s", hdev->name);
+-
+- if (!hci_conn_num(hdev, ESCO_LINK))
+- return;
++ /* Use sco_pkts if flow control has not been enabled which will limit
++ * the amount of buffer sent in a row.
++ */
++ if (!hci_dev_test_flag(hdev, HCI_SCO_FLOWCTL))
++ cnt = &pkts;
++ else
++ cnt = &hdev->sco_cnt;
+
+- while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK,
+- "e))) {
++ while (*cnt && (conn = hci_low_sent(hdev, type, "e))) {
+ while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+ BT_DBG("skb %p len %d", skb, skb->len);
+ hci_send_frame(hdev, skb);
+@@ -3599,8 +3584,17 @@ static void hci_sched_esco(struct hci_de
+ conn->sent++;
+ if (conn->sent == ~0)
+ conn->sent = 0;
++ (*cnt)--;
+ }
+ }
++
++ /* Rescheduled if all packets were sent and flow control is not enabled
++ * as there could be more packets queued that could not be sent and
++ * since no HCI_EV_NUM_COMP_PKTS event will be generated the reschedule
++ * needs to be forced.
++ */
++ if (!pkts && !hci_dev_test_flag(hdev, HCI_SCO_FLOWCTL))
++ queue_work(hdev->workqueue, &hdev->tx_work);
+ }
+
+ static void hci_sched_acl_pkt(struct hci_dev *hdev)
+@@ -3636,8 +3630,8 @@ static void hci_sched_acl_pkt(struct hci
+ chan->conn->sent++;
+
+ /* Send pending SCO packets right away */
+- hci_sched_sco(hdev);
+- hci_sched_esco(hdev);
++ hci_sched_sco(hdev, SCO_LINK);
++ hci_sched_sco(hdev, ESCO_LINK);
+ }
+ }
+
+@@ -3692,8 +3686,8 @@ static void hci_sched_le(struct hci_dev
+ chan->conn->sent++;
+
+ /* Send pending SCO packets right away */
+- hci_sched_sco(hdev);
+- hci_sched_esco(hdev);
++ hci_sched_sco(hdev, SCO_LINK);
++ hci_sched_sco(hdev, ESCO_LINK);
+ }
+ }
+
+@@ -3738,8 +3732,8 @@ static void hci_tx_work(struct work_stru
+
+ if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
+ /* Schedule queues and send stuff to HCI driver */
+- hci_sched_sco(hdev);
+- hci_sched_esco(hdev);
++ hci_sched_sco(hdev, SCO_LINK);
++ hci_sched_sco(hdev, ESCO_LINK);
+ hci_sched_iso(hdev);
+ hci_sched_acl(hdev);
+ hci_sched_le(hdev);
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -4445,9 +4445,11 @@ static void hci_num_comp_pkts_evt(struct
+ break;
+
+ case SCO_LINK:
++ case ESCO_LINK:
+ hdev->sco_cnt += count;
+ if (hdev->sco_cnt > hdev->sco_pkts)
+ hdev->sco_cnt = hdev->sco_pkts;
++
+ break;
+
+ case ISO_LINK:
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -3877,6 +3877,28 @@ static int hci_write_ca_timeout_sync(str
+ sizeof(param), ¶m, HCI_CMD_TIMEOUT);
+ }
+
++/* Enable SCO flow control if supported */
++static int hci_write_sync_flowctl_sync(struct hci_dev *hdev)
++{
++ struct hci_cp_write_sync_flowctl cp;
++ int err;
++
++ /* Check if the controller supports SCO and HCI_OP_WRITE_SYNC_FLOWCTL */
++ if (!lmp_sco_capable(hdev) || !(hdev->commands[10] & BIT(4)) ||
++ !test_bit(HCI_QUIRK_SYNC_FLOWCTL_SUPPORTED, &hdev->quirks))
++ return 0;
++
++ memset(&cp, 0, sizeof(cp));
++ cp.enable = 0x01;
++
++ err = __hci_cmd_sync_status(hdev, HCI_OP_WRITE_SYNC_FLOWCTL,
++ sizeof(cp), &cp, HCI_CMD_TIMEOUT);
++ if (!err)
++ hci_dev_set_flag(hdev, HCI_SCO_FLOWCTL);
++
++ return err;
++}
++
+ /* BR Controller init stage 2 command sequence */
+ static const struct hci_init_stage br_init2[] = {
+ /* HCI_OP_READ_BUFFER_SIZE */
+@@ -3895,6 +3917,8 @@ static const struct hci_init_stage br_in
+ HCI_INIT(hci_clear_event_filter_sync),
+ /* HCI_OP_WRITE_CA_TIMEOUT */
+ HCI_INIT(hci_write_ca_timeout_sync),
++ /* HCI_OP_WRITE_SYNC_FLOWCTL */
++ HCI_INIT(hci_write_sync_flowctl_sync),
+ {}
+ };
+
--- /dev/null
+From stable+bounces-275098-greg=kroah.com@vger.kernel.org Thu Jul 16 01:56:21 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jul 2026 19:55:28 -0400
+Subject: Bluetooth: hci_sync: annotate data-races around hdev->req_status
+To: stable@vger.kernel.org
+Cc: Cen Zhang <zzzccc427@gmail.com>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260715235529.525959-3-sashal@kernel.org>
+
+From: Cen Zhang <zzzccc427@gmail.com>
+
+[ Upstream commit b6807cfc195ef99e1ac37b2e1e60df40295daa8c ]
+
+__hci_cmd_sync_sk() sets hdev->req_status under hdev->req_lock:
+
+ hdev->req_status = HCI_REQ_PEND;
+
+However, several other functions read or write hdev->req_status without
+holding any lock:
+
+ - hci_send_cmd_sync() reads req_status in hci_cmd_work (workqueue)
+ - hci_cmd_sync_complete() reads/writes from HCI event completion
+ - hci_cmd_sync_cancel() / hci_cmd_sync_cancel_sync() read/write
+ - hci_abort_conn() reads in connection abort path
+
+Since __hci_cmd_sync_sk() runs on hdev->req_workqueue while
+hci_send_cmd_sync() runs on hdev->workqueue, these are different
+workqueues that can execute concurrently on different CPUs. The plain
+C accesses constitute a data race.
+
+Add READ_ONCE()/WRITE_ONCE() annotations on all concurrent accesses
+to hdev->req_status to prevent potential compiler optimizations that
+could affect correctness (e.g., load fusing in the wait_event
+condition or store reordering).
+
+Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: 12917f591cea ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/hci_core.c | 2 +-
+ net/bluetooth/hci_sync.c | 20 ++++++++++----------
+ 2 files changed, 11 insertions(+), 11 deletions(-)
+
+--- a/net/bluetooth/hci_core.c
++++ b/net/bluetooth/hci_core.c
+@@ -4060,7 +4060,7 @@ static void hci_send_cmd_sync(struct hci
+ return;
+ }
+
+- if (hci_req_status_pend(hdev) &&
++ if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND &&
+ !hci_dev_test_and_set_flag(hdev, HCI_CMD_PENDING)) {
+ kfree_skb(hdev->req_skb);
+ hdev->req_skb = skb_clone(hdev->sent_cmd, GFP_KERNEL);
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -25,11 +25,11 @@ static void hci_cmd_sync_complete(struct
+ {
+ bt_dev_dbg(hdev, "result 0x%2.2x", result);
+
+- if (hdev->req_status != HCI_REQ_PEND)
++ if (READ_ONCE(hdev->req_status) != HCI_REQ_PEND)
+ return;
+
+ hdev->req_result = result;
+- hdev->req_status = HCI_REQ_DONE;
++ WRITE_ONCE(hdev->req_status, HCI_REQ_DONE);
+
+ /* Free the request command so it is not used as response */
+ kfree_skb(hdev->req_skb);
+@@ -168,20 +168,20 @@ struct sk_buff *__hci_cmd_sync_sk(struct
+
+ hci_cmd_sync_add(&req, opcode, plen, param, event, sk);
+
+- hdev->req_status = HCI_REQ_PEND;
++ WRITE_ONCE(hdev->req_status, HCI_REQ_PEND);
+
+ err = hci_req_sync_run(&req);
+ if (err < 0)
+ return ERR_PTR(err);
+
+ err = wait_event_interruptible_timeout(hdev->req_wait_q,
+- hdev->req_status != HCI_REQ_PEND,
++ READ_ONCE(hdev->req_status) != HCI_REQ_PEND,
+ timeout);
+
+ if (err == -ERESTARTSYS)
+ return ERR_PTR(-EINTR);
+
+- switch (hdev->req_status) {
++ switch (READ_ONCE(hdev->req_status)) {
+ case HCI_REQ_DONE:
+ err = -bt_to_errno(hdev->req_result);
+ break;
+@@ -195,7 +195,7 @@ struct sk_buff *__hci_cmd_sync_sk(struct
+ break;
+ }
+
+- hdev->req_status = 0;
++ WRITE_ONCE(hdev->req_status, 0);
+ hdev->req_result = 0;
+ skb = hdev->req_rsp;
+ hdev->req_rsp = NULL;
+@@ -689,9 +689,9 @@ void hci_cmd_sync_cancel(struct hci_dev
+ {
+ bt_dev_dbg(hdev, "err 0x%2.2x", err);
+
+- if (hdev->req_status == HCI_REQ_PEND) {
++ if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
+ hdev->req_result = err;
+- hdev->req_status = HCI_REQ_CANCELED;
++ WRITE_ONCE(hdev->req_status, HCI_REQ_CANCELED);
+
+ queue_work(hdev->workqueue, &hdev->cmd_sync_cancel_work);
+ }
+@@ -707,12 +707,12 @@ void hci_cmd_sync_cancel_sync(struct hci
+ {
+ bt_dev_dbg(hdev, "err 0x%2.2x", err);
+
+- if (hdev->req_status == HCI_REQ_PEND) {
++ if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
+ /* 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;
++ WRITE_ONCE(hdev->req_status, HCI_REQ_CANCELED);
+
+ wake_up_interruptible(&hdev->req_wait_q);
+ }
--- /dev/null
+From stable+bounces-275099-greg=kroah.com@vger.kernel.org Thu Jul 16 01:55:45 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jul 2026 19:55:27 -0400
+Subject: Bluetooth: separate CIS_LINK and BIS_LINK link types
+To: stable@vger.kernel.org
+Cc: Pauli Virtanen <pav@iki.fi>, Luiz Augusto von Dentz <luiz.von.dentz@intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260715235529.525959-2-sashal@kernel.org>
+
+From: Pauli Virtanen <pav@iki.fi>
+
+[ Upstream commit 23205562ffc8de20f57afdd984858cab29e77968 ]
+
+Use separate link type id for unicast and broadcast ISO connections.
+These connection types are handled with separate HCI commands, socket
+API is different, and hci_conn has union fields that are different in
+the two cases, so they shall not be mixed up.
+
+Currently in most places it is attempted to distinguish ucast by
+bacmp(&c->dst, BDADDR_ANY) but it is wrong as dst is set for bcast sink
+hci_conn in iso_conn_ready(). Additionally checking sync_handle might be
+OK, but depends on details of bcast conn configuration flow.
+
+To avoid complicating it, use separate link types.
+
+Fixes: f764a6c2c1e4 ("Bluetooth: ISO: Add broadcast support")
+Signed-off-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: 12917f591cea ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/bluetooth/hci.h | 3 ++-
+ include/net/bluetooth/hci_core.h | 38 +++++++++++++++++++++-----------------
+ net/bluetooth/hci_conn.c | 37 ++++++++++++++++++++++---------------
+ net/bluetooth/hci_core.c | 21 +++++++++++++--------
+ net/bluetooth/hci_event.c | 25 +++++++++++++------------
+ net/bluetooth/hci_sync.c | 14 +++++++++-----
+ net/bluetooth/iso.c | 4 ++--
+ net/bluetooth/mgmt.c | 3 ++-
+ 8 files changed, 84 insertions(+), 61 deletions(-)
+
+--- a/include/net/bluetooth/hci.h
++++ b/include/net/bluetooth/hci.h
+@@ -527,7 +527,8 @@ enum {
+ #define ESCO_LINK 0x02
+ /* Low Energy links do not have defined link type. Use invented one */
+ #define LE_LINK 0x80
+-#define ISO_LINK 0x82
++#define CIS_LINK 0x82
++#define BIS_LINK 0x83
+ #define INVALID_LINK 0xff
+
+ /* LMP features */
+--- a/include/net/bluetooth/hci_core.h
++++ b/include/net/bluetooth/hci_core.h
+@@ -995,7 +995,8 @@ static inline void hci_conn_hash_add(str
+ case ESCO_LINK:
+ h->sco_num++;
+ break;
+- case ISO_LINK:
++ case CIS_LINK:
++ case BIS_LINK:
+ h->iso_num++;
+ break;
+ }
+@@ -1021,7 +1022,8 @@ static inline void hci_conn_hash_del(str
+ case ESCO_LINK:
+ h->sco_num--;
+ break;
+- case ISO_LINK:
++ case CIS_LINK:
++ case BIS_LINK:
+ h->iso_num--;
+ break;
+ }
+@@ -1038,7 +1040,8 @@ static inline unsigned int hci_conn_num(
+ case SCO_LINK:
+ case ESCO_LINK:
+ return h->sco_num;
+- case ISO_LINK:
++ case CIS_LINK:
++ case BIS_LINK:
+ return h->iso_num;
+ default:
+ return 0;
+@@ -1099,7 +1102,7 @@ static inline struct hci_conn *hci_conn_
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+- if (bacmp(&c->dst, ba) || c->type != ISO_LINK)
++ if (bacmp(&c->dst, ba) || c->type != BIS_LINK)
+ continue;
+
+ if (c->iso_qos.bcast.bis == bis) {
+@@ -1123,8 +1126,8 @@ hci_conn_hash_lookup_per_adv_bis(struct
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+- if (bacmp(&c->dst, ba) || c->type != ISO_LINK ||
+- !test_bit(HCI_CONN_PER_ADV, &c->flags))
++ if (bacmp(&c->dst, ba) || c->type != BIS_LINK ||
++ !test_bit(HCI_CONN_PER_ADV, &c->flags))
+ continue;
+
+ if (c->iso_qos.bcast.big == big &&
+@@ -1234,7 +1237,7 @@ static inline struct hci_conn *hci_conn_
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+- if (c->type != ISO_LINK || !bacmp(&c->dst, BDADDR_ANY))
++ if (c->type != CIS_LINK)
+ continue;
+
+ /* Match CIG ID if set */
+@@ -1266,7 +1269,7 @@ static inline struct hci_conn *hci_conn_
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+- if (c->type != ISO_LINK || !bacmp(&c->dst, BDADDR_ANY))
++ if (c->type != CIS_LINK)
+ continue;
+
+ if (handle == c->iso_qos.ucast.cig) {
+@@ -1289,7 +1292,7 @@ static inline struct hci_conn *hci_conn_
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+- if (bacmp(&c->dst, BDADDR_ANY) || c->type != ISO_LINK)
++ if (bacmp(&c->dst, BDADDR_ANY) || c->type != BIS_LINK)
+ continue;
+
+ if (handle == c->iso_qos.bcast.big) {
+@@ -1312,7 +1315,7 @@ static inline struct hci_conn *hci_conn_
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+- if (c->type != ISO_LINK)
++ if (c->type != BIS_LINK)
+ continue;
+
+ if (handle != BT_ISO_QOS_BIG_UNSET && handle == c->iso_qos.bcast.big) {
+@@ -1335,8 +1338,8 @@ hci_conn_hash_lookup_big_state(struct hc
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+- if (bacmp(&c->dst, BDADDR_ANY) || c->type != ISO_LINK ||
+- c->state != state)
++ if (c->type != BIS_LINK || bacmp(&c->dst, BDADDR_ANY) ||
++ c->state != state)
+ continue;
+
+ if (handle == c->iso_qos.bcast.big) {
+@@ -1359,8 +1362,8 @@ hci_conn_hash_lookup_pa_sync_big_handle(
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+- if (c->type != ISO_LINK ||
+- !test_bit(HCI_CONN_PA_SYNC, &c->flags))
++ if (c->type != BIS_LINK ||
++ !test_bit(HCI_CONN_PA_SYNC, &c->flags))
+ continue;
+
+ if (c->iso_qos.bcast.big == big) {
+@@ -1382,8 +1385,8 @@ hci_conn_hash_lookup_pa_sync_handle(stru
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+- if (c->type != ISO_LINK ||
+- !test_bit(HCI_CONN_PA_SYNC, &c->flags))
++ if (c->type != BIS_LINK ||
++ !test_bit(HCI_CONN_PA_SYNC, &c->flags))
+ continue;
+
+ if (c->sync_handle == sync_handle) {
+@@ -1959,7 +1962,8 @@ static inline int hci_proto_connect_ind(
+ case ESCO_LINK:
+ return sco_connect_ind(hdev, bdaddr, flags);
+
+- case ISO_LINK:
++ case CIS_LINK:
++ case BIS_LINK:
+ return iso_connect_ind(hdev, bdaddr, flags);
+
+ default:
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -870,9 +870,11 @@ static void cis_cleanup(struct hci_conn
+ /* Check if ISO connection is a CIS and remove CIG if there are
+ * no other connections using it.
+ */
+- hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_BOUND, &d);
+- hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECT, &d);
+- hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECTED, &d);
++ hci_conn_hash_list_state(hdev, find_cis, CIS_LINK, BT_BOUND, &d);
++ hci_conn_hash_list_state(hdev, find_cis, CIS_LINK, BT_CONNECT,
++ &d);
++ hci_conn_hash_list_state(hdev, find_cis, CIS_LINK, BT_CONNECTED,
++ &d);
+ if (d.count)
+ return;
+
+@@ -895,7 +897,8 @@ static struct hci_conn *__hci_conn_add(s
+ if (!hdev->acl_mtu)
+ return ERR_PTR(-ECONNREFUSED);
+ break;
+- case ISO_LINK:
++ case CIS_LINK:
++ case BIS_LINK:
+ if (hdev->iso_mtu)
+ /* Dedicated ISO Buffer exists */
+ break;
+@@ -959,7 +962,8 @@ static struct hci_conn *__hci_conn_add(s
+ hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
+ conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
+ break;
+- case ISO_LINK:
++ case CIS_LINK:
++ case BIS_LINK:
+ /* conn->src should reflect the local identity address */
+ hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
+
+@@ -1055,7 +1059,8 @@ static void hci_conn_cleanup_child(struc
+ if (HCI_CONN_HANDLE_UNSET(conn->handle))
+ hci_conn_failed(conn, reason);
+ break;
+- case ISO_LINK:
++ case CIS_LINK:
++ case BIS_LINK:
+ if ((conn->state != BT_CONNECTED &&
+ !test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) ||
+ test_bit(HCI_CONN_BIG_CREATED, &conn->flags))
+@@ -1130,7 +1135,8 @@ void hci_conn_del(struct hci_conn *conn)
+ hdev->acl_cnt += conn->sent;
+ } else {
+ /* Unacked ISO frames */
+- if (conn->type == ISO_LINK) {
++ if (conn->type == CIS_LINK ||
++ conn->type == BIS_LINK) {
+ if (hdev->iso_pkts)
+ hdev->iso_cnt += conn->sent;
+ else if (hdev->le_pkts)
+@@ -1501,7 +1507,7 @@ static struct hci_conn *hci_add_bis(stru
+ memcmp(conn->le_per_adv_data, base, base_len)))
+ return ERR_PTR(-EADDRINUSE);
+
+- conn = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
++ conn = hci_conn_add_unset(hdev, BIS_LINK, dst, HCI_ROLE_MASTER);
+ if (IS_ERR(conn))
+ return conn;
+
+@@ -1707,7 +1713,7 @@ static int hci_le_create_big(struct hci_
+ data.count = 0;
+
+ /* Create a BIS for each bound connection */
+- hci_conn_hash_list_state(hdev, bis_list, ISO_LINK,
++ hci_conn_hash_list_state(hdev, bis_list, BIS_LINK,
+ BT_BOUND, &data);
+
+ cp.handle = qos->bcast.big;
+@@ -1803,12 +1809,12 @@ static bool hci_le_set_cig_params(struct
+ for (data.cig = 0x00; data.cig < 0xf0; data.cig++) {
+ data.count = 0;
+
+- hci_conn_hash_list_state(hdev, find_cis, ISO_LINK,
++ hci_conn_hash_list_state(hdev, find_cis, CIS_LINK,
+ BT_CONNECT, &data);
+ if (data.count)
+ continue;
+
+- hci_conn_hash_list_state(hdev, find_cis, ISO_LINK,
++ hci_conn_hash_list_state(hdev, find_cis, CIS_LINK,
+ BT_CONNECTED, &data);
+ if (!data.count)
+ break;
+@@ -1860,7 +1866,8 @@ struct hci_conn *hci_bind_cis(struct hci
+ cis = hci_conn_hash_lookup_cis(hdev, dst, dst_type, qos->ucast.cig,
+ qos->ucast.cis);
+ if (!cis) {
+- cis = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
++ cis = hci_conn_add_unset(hdev, CIS_LINK, dst,
++ HCI_ROLE_MASTER);
+ if (IS_ERR(cis))
+ return cis;
+ cis->cleanup = cis_cleanup;
+@@ -1950,7 +1957,7 @@ bool hci_iso_setup_path(struct hci_conn
+
+ int hci_conn_check_create_cis(struct hci_conn *conn)
+ {
+- if (conn->type != ISO_LINK || !bacmp(&conn->dst, BDADDR_ANY))
++ if (conn->type != CIS_LINK)
+ return -EINVAL;
+
+ if (!conn->parent || conn->parent->state != BT_CONNECTED ||
+@@ -2248,7 +2255,7 @@ struct hci_conn *hci_connect_bis(struct
+ * the start periodic advertising and create BIG commands have
+ * been queued
+ */
+- hci_conn_hash_list_state(hdev, bis_mark_per_adv, ISO_LINK,
++ hci_conn_hash_list_state(hdev, bis_mark_per_adv, BIS_LINK,
+ BT_BOUND, &data);
+
+ /* Queue start periodic advertising and create BIG */
+@@ -2910,7 +2917,7 @@ int hci_abort_conn(struct hci_conn *conn
+ * hci_connect_le serializes the connection attempts so only one
+ * connection can be in BT_CONNECT at time.
+ */
+- if (conn->state == BT_CONNECT && hdev->req_status == HCI_REQ_PEND) {
++ if (conn->state == BT_CONNECT && READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
+ switch (hci_skb_event(hdev->sent_cmd)) {
+ case HCI_EV_CONN_COMPLETE:
+ case HCI_EV_LE_CONN_COMPLETE:
+--- a/net/bluetooth/hci_core.c
++++ b/net/bluetooth/hci_core.c
+@@ -2907,12 +2907,13 @@ int hci_recv_frame(struct hci_dev *hdev,
+ break;
+ case HCI_ACLDATA_PKT:
+ /* Detect if ISO packet has been sent as ACL */
+- if (hci_conn_num(hdev, ISO_LINK)) {
++ if (hci_conn_num(hdev, CIS_LINK) ||
++ hci_conn_num(hdev, BIS_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)
++ if (type == CIS_LINK || type == BIS_LINK)
+ hci_skb_pkt_type(skb) = HCI_ISODATA_PKT;
+ }
+ break;
+@@ -3347,7 +3348,8 @@ static inline void hci_quote_sent(struct
+ case LE_LINK:
+ cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
+ break;
+- case ISO_LINK:
++ case CIS_LINK:
++ case BIS_LINK:
+ cnt = hdev->iso_mtu ? hdev->iso_cnt :
+ hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
+ break;
+@@ -3361,7 +3363,7 @@ static inline void hci_quote_sent(struct
+ }
+
+ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,
+- int *quote)
++ __u8 type2, int *quote)
+ {
+ struct hci_conn_hash *h = &hdev->conn_hash;
+ struct hci_conn *conn = NULL, *c;
+@@ -3373,7 +3375,8 @@ static struct hci_conn *hci_low_sent(str
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(c, &h->list, list) {
+- if (c->type != type || skb_queue_empty(&c->data_q))
++ if ((c->type != type && c->type != type2) ||
++ skb_queue_empty(&c->data_q))
+ continue;
+
+ if (c->state != BT_CONNECTED && c->state != BT_CONFIG)
+@@ -3576,7 +3579,7 @@ static void hci_sched_sco(struct hci_dev
+ else
+ cnt = &hdev->sco_cnt;
+
+- while (*cnt && (conn = hci_low_sent(hdev, type, "e))) {
++ while (*cnt && (conn = hci_low_sent(hdev, type, type, "e))) {
+ while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+ BT_DBG("skb %p len %d", skb, skb->len);
+ hci_send_frame(hdev, skb);
+@@ -3704,12 +3707,14 @@ static void hci_sched_iso(struct hci_dev
+
+ BT_DBG("%s", hdev->name);
+
+- if (!hci_conn_num(hdev, ISO_LINK))
++ if (!hci_conn_num(hdev, CIS_LINK) &&
++ !hci_conn_num(hdev, BIS_LINK))
+ return;
+
+ cnt = hdev->iso_pkts ? &hdev->iso_cnt :
+ hdev->le_pkts ? &hdev->le_cnt : &hdev->acl_cnt;
+- while (*cnt && (conn = hci_low_sent(hdev, ISO_LINK, "e))) {
++ while (*cnt && (conn = hci_low_sent(hdev, CIS_LINK, BIS_LINK,
++ "e))) {
+ while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+ BT_DBG("skb %p len %d", skb, skb->len);
+ hci_send_frame(hdev, skb);
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -3776,7 +3776,7 @@ static void hci_unbound_cis_failed(struc
+ lockdep_assert_held(&hdev->lock);
+
+ list_for_each_entry_safe(conn, tmp, &hdev->conn_hash.list, list) {
+- if (conn->type != ISO_LINK || !bacmp(&conn->dst, BDADDR_ANY) ||
++ if (conn->type != CIS_LINK ||
+ conn->state == BT_OPEN || conn->iso_qos.ucast.cig != cig)
+ continue;
+
+@@ -4452,7 +4452,8 @@ static void hci_num_comp_pkts_evt(struct
+
+ break;
+
+- case ISO_LINK:
++ case CIS_LINK:
++ case BIS_LINK:
+ if (hdev->iso_pkts) {
+ hdev->iso_cnt += count;
+ if (hdev->iso_cnt > hdev->iso_pkts)
+@@ -6384,7 +6385,7 @@ static void hci_le_pa_sync_estabilished_
+
+ hci_dev_clear_flag(hdev, HCI_PA_SYNC);
+
+- mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ISO_LINK, &flags);
++ mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, BIS_LINK, &flags);
+ if (!(mask & HCI_LM_ACCEPT)) {
+ hci_le_pa_term_sync(hdev, ev->handle);
+ goto unlock;
+@@ -6395,7 +6396,7 @@ static void hci_le_pa_sync_estabilished_
+
+ if (ev->status) {
+ /* Add connection to indicate the failed PA sync event */
+- pa_sync = hci_conn_add_unset(hdev, ISO_LINK, BDADDR_ANY,
++ pa_sync = hci_conn_add_unset(hdev, BIS_LINK, BDADDR_ANY,
+ HCI_ROLE_SLAVE);
+
+ if (!pa_sync)
+@@ -6422,7 +6423,7 @@ static void hci_le_per_adv_report_evt(st
+
+ hci_dev_lock(hdev);
+
+- mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, ISO_LINK, &flags);
++ mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, BIS_LINK, &flags);
+ if (!(mask & HCI_LM_ACCEPT))
+ hci_le_pa_term_sync(hdev, ev->sync_handle);
+
+@@ -6693,7 +6694,7 @@ static void hci_le_cis_estabilished_evt(
+ goto unlock;
+ }
+
+- if (conn->type != ISO_LINK) {
++ if (conn->type != CIS_LINK) {
+ bt_dev_err(hdev,
+ "Invalid connection link type handle 0x%4.4x",
+ handle);
+@@ -6811,7 +6812,7 @@ static void hci_le_cis_req_evt(struct hc
+ if (!acl)
+ goto unlock;
+
+- mask = hci_proto_connect_ind(hdev, &acl->dst, ISO_LINK, &flags);
++ mask = hci_proto_connect_ind(hdev, &acl->dst, CIS_LINK, &flags);
+ if (!(mask & HCI_LM_ACCEPT)) {
+ hci_le_reject_cis(hdev, ev->cis_handle);
+ goto unlock;
+@@ -6819,8 +6820,8 @@ static void hci_le_cis_req_evt(struct hc
+
+ cis = hci_conn_hash_lookup_handle(hdev, cis_handle);
+ if (!cis) {
+- cis = hci_conn_add(hdev, ISO_LINK, &acl->dst, HCI_ROLE_SLAVE,
+- cis_handle);
++ cis = hci_conn_add(hdev, CIS_LINK, &acl->dst,
++ HCI_ROLE_SLAVE, cis_handle);
+ if (IS_ERR(cis)) {
+ hci_le_reject_cis(hdev, ev->cis_handle);
+ goto unlock;
+@@ -6954,7 +6955,7 @@ static void hci_le_big_sync_established_
+ bt_dev_dbg(hdev, "ignore too large handle %u", handle);
+ continue;
+ }
+- bis = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY,
++ bis = hci_conn_add(hdev, BIS_LINK, BDADDR_ANY,
+ HCI_ROLE_SLAVE, handle);
+ if (IS_ERR(bis))
+ continue;
+@@ -7011,7 +7012,7 @@ static void hci_le_big_info_adv_report_e
+
+ hci_dev_lock(hdev);
+
+- mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, ISO_LINK, &flags);
++ mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, BIS_LINK, &flags);
+ if (!(mask & HCI_LM_ACCEPT)) {
+ hci_le_pa_term_sync(hdev, ev->sync_handle);
+ goto unlock;
+@@ -7028,7 +7029,7 @@ static void hci_le_big_info_adv_report_e
+ goto unlock;
+
+ /* Add connection to indicate the PA sync event */
+- pa_sync = hci_conn_add_unset(hdev, ISO_LINK, BDADDR_ANY,
++ pa_sync = hci_conn_add_unset(hdev, BIS_LINK, BDADDR_ANY,
+ HCI_ROLE_SLAVE);
+
+ if (IS_ERR(pa_sync))
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -2971,7 +2971,7 @@ static int hci_le_set_ext_scan_param_syn
+ if (sent) {
+ struct hci_conn *conn;
+
+- conn = hci_conn_hash_lookup_ba(hdev, ISO_LINK,
++ conn = hci_conn_hash_lookup_ba(hdev, BIS_LINK,
+ &sent->bdaddr);
+ if (conn) {
+ struct bt_iso_qos *qos = &conn->iso_qos;
+@@ -5582,7 +5582,7 @@ static int hci_connect_cancel_sync(struc
+ if (conn->type == LE_LINK)
+ return hci_le_connect_cancel_sync(hdev, conn, reason);
+
+- if (conn->type == ISO_LINK) {
++ if (conn->type == CIS_LINK) {
+ /* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E
+ * page 1857:
+ *
+@@ -5595,9 +5595,10 @@ static int hci_connect_cancel_sync(struc
+ return hci_disconnect_sync(hdev, conn, reason);
+
+ /* CIS with no Create CIS sent have nothing to cancel */
+- if (bacmp(&conn->dst, BDADDR_ANY))
+- return HCI_ERROR_LOCAL_HOST_TERM;
++ return HCI_ERROR_LOCAL_HOST_TERM;
++ }
+
++ if (conn->type == BIS_LINK) {
+ /* There is no way to cancel a BIS without terminating the BIG
+ * which is done later on connection cleanup.
+ */
+@@ -5659,9 +5660,12 @@ static int hci_reject_conn_sync(struct h
+ {
+ struct hci_cp_reject_conn_req cp;
+
+- if (conn->type == ISO_LINK)
++ if (conn->type == CIS_LINK)
+ return hci_le_reject_cis_sync(hdev, conn, reason);
+
++ if (conn->type == BIS_LINK)
++ return -EINVAL;
++
+ if (conn->type == SCO_LINK || conn->type == ESCO_LINK)
+ return hci_reject_sco_sync(hdev, conn, reason);
+
+--- a/net/bluetooth/iso.c
++++ b/net/bluetooth/iso.c
+@@ -1963,7 +1963,7 @@ done:
+
+ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
+ {
+- if (hcon->type != ISO_LINK) {
++ if (hcon->type != CIS_LINK && hcon->type != BIS_LINK) {
+ if (hcon->type != LE_LINK)
+ return;
+
+@@ -2004,7 +2004,7 @@ static void iso_connect_cfm(struct hci_c
+
+ static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason)
+ {
+- if (hcon->type != ISO_LINK)
++ if (hcon->type != CIS_LINK && hcon->type != BIS_LINK)
+ return;
+
+ BT_DBG("hcon %p reason %d", hcon, reason);
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -3233,7 +3233,8 @@ failed:
+ static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
+ {
+ switch (link_type) {
+- case ISO_LINK:
++ case CIS_LINK:
++ case BIS_LINK:
+ case LE_LINK:
+ switch (addr_type) {
+ case ADDR_LE_DEV_PUBLIC:
exfat-preserve-benign-secondary-entries-during-rename-and-move.patch
btrfs-fix-false-io-failure-after-falling-back-to-buffered-write.patch
btrfs-fix-incorrect-buffered-io-fallback-for-append-direct-writes.patch
+bluetooth-hci_core-enable-buffer-flow-control-for-sco-esco.patch
+bluetooth-separate-cis_link-and-bis_link-link-types.patch
+bluetooth-hci_sync-annotate-data-races-around-hdev-req_status.patch
+bluetooth-hci_conn-fix-null-ptr-deref-in-hci_abort_conn.patch