]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 21 Jul 2026 14:07:35 +0000 (16:07 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 21 Jul 2026 14:07:35 +0000 (16:07 +0200)
added patches:
bluetooth-hci_conn-fix-null-ptr-deref-in-hci_abort_conn.patch
bluetooth-hci_core-enable-buffer-flow-control-for-sco-esco.patch
bluetooth-hci_sync-annotate-data-races-around-hdev-req_status.patch
bluetooth-separate-cis_link-and-bis_link-link-types.patch

queue-6.6/bluetooth-hci_conn-fix-null-ptr-deref-in-hci_abort_conn.patch [new file with mode: 0644]
queue-6.6/bluetooth-hci_core-enable-buffer-flow-control-for-sco-esco.patch [new file with mode: 0644]
queue-6.6/bluetooth-hci_sync-annotate-data-races-around-hdev-req_status.patch [new file with mode: 0644]
queue-6.6/bluetooth-separate-cis_link-and-bis_link-link-types.patch [new file with mode: 0644]
queue-6.6/series

diff --git a/queue-6.6/bluetooth-hci_conn-fix-null-ptr-deref-in-hci_abort_conn.patch b/queue-6.6/bluetooth-hci_conn-fix-null-ptr-deref-in-hci_abort_conn.patch
new file mode 100644 (file)
index 0000000..d98372a
--- /dev/null
@@ -0,0 +1,281 @@
+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;
+ }
diff --git a/queue-6.6/bluetooth-hci_core-enable-buffer-flow-control-for-sco-esco.patch b/queue-6.6/bluetooth-hci_core-enable-buffer-flow-control-for-sco-esco.patch
new file mode 100644 (file)
index 0000000..e244d88
--- /dev/null
@@ -0,0 +1,271 @@
+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, &quote))) {
+-              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,
+-                                                   &quote))) {
++      while (*cnt && (conn = hci_low_sent(hdev, type, &quote))) {
+               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), &param, 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),
+       {}
+ };
diff --git a/queue-6.6/bluetooth-hci_sync-annotate-data-races-around-hdev-req_status.patch b/queue-6.6/bluetooth-hci_sync-annotate-data-races-around-hdev-req_status.patch
new file mode 100644 (file)
index 0000000..1f445a7
--- /dev/null
@@ -0,0 +1,131 @@
+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);
+       }
diff --git a/queue-6.6/bluetooth-separate-cis_link-and-bis_link-link-types.patch b/queue-6.6/bluetooth-separate-cis_link-and-bis_link-link-types.patch
new file mode 100644 (file)
index 0000000..734fec4
--- /dev/null
@@ -0,0 +1,567 @@
+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, &quote))) {
++      while (*cnt && (conn = hci_low_sent(hdev, type, type, &quote))) {
+               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, &quote))) {
++      while (*cnt && (conn = hci_low_sent(hdev, CIS_LINK, BIS_LINK,
++                                          &quote))) {
+               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:
index 57608333ee67681aba4be153ffb868d267db1a13..a01571310052791c45b653843cee861e0b2cd7fc 100644 (file)
@@ -1244,3 +1244,7 @@ exfat-move-exfat_chain_set-out-of-__exfat_resolve_path.patch
 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