From: Greg Kroah-Hartman Date: Tue, 21 Jul 2026 14:07:35 +0000 (+0200) Subject: 6.6-stable patches X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=53456ac25c49c17583e101a1915f2c6929f8289d;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches 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 --- 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 index 0000000000..d98372afc4 --- /dev/null +++ b/queue-6.6/bluetooth-hci_conn-fix-null-ptr-deref-in-hci_abort_conn.patch @@ -0,0 +1,281 @@ +From stable+bounces-275100-greg=kroah.com@vger.kernel.org Thu Jul 16 01:55:45 2026 +From: Sasha Levin +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 , XIAO WU , Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260715235529.525959-4-sashal@kernel.org> + +From: Siwei Zhang + +[ 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 +Assisted-by: Claude:claude-opus-4-8 +Signed-off-by: Siwei Zhang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..e244d88964 --- /dev/null +++ b/queue-6.6/bluetooth-hci_core-enable-buffer-flow-control-for-sco-esco.patch @@ -0,0 +1,271 @@ +From stable+bounces-275097-greg=kroah.com@vger.kernel.org Thu Jul 16 01:55:36 2026 +From: Sasha Levin +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 , Pauli Virtanen , Sasha Levin +Message-ID: <20260715235529.525959-1-sashal@kernel.org> + +From: Luiz Augusto von Dentz + +[ 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 +Tested-by: Pauli Virtanen +Stable-dep-of: 12917f591cea ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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), + {} + }; + 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 index 0000000000..1f445a77b5 --- /dev/null +++ b/queue-6.6/bluetooth-hci_sync-annotate-data-races-around-hdev-req_status.patch @@ -0,0 +1,131 @@ +From stable+bounces-275098-greg=kroah.com@vger.kernel.org Thu Jul 16 01:56:21 2026 +From: Sasha Levin +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 , Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260715235529.525959-3-sashal@kernel.org> + +From: Cen Zhang + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Stable-dep-of: 12917f591cea ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..734fec448d --- /dev/null +++ b/queue-6.6/bluetooth-separate-cis_link-and-bis_link-link-types.patch @@ -0,0 +1,567 @@ +From stable+bounces-275099-greg=kroah.com@vger.kernel.org Thu Jul 16 01:55:45 2026 +From: Sasha Levin +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 , Luiz Augusto von Dentz , Sasha Levin +Message-ID: <20260715235529.525959-2-sashal@kernel.org> + +From: Pauli Virtanen + +[ 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 +Signed-off-by: Luiz Augusto von Dentz +Stable-dep-of: 12917f591cea ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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: diff --git a/queue-6.6/series b/queue-6.6/series index 57608333ee..a015713100 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -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