Add the RHEL 211.19.1..211.20.1 backports (1245-1287) from centos-stream-10 and upstream, on top of 211.18.1, plus the dpll RHEL kABI adaptation (1287). RHEL now ships the smb cifs.spnego fix too; the existing ahead-fix 1105 is byte-identical, so RHEL's redundant copy is omitted. Bump to 211.20.1.
301 lines
8.5 KiB
Diff
301 lines
8.5 KiB
Diff
From 414511072bcdf8a60a29bf43cca47260006df84b Mon Sep 17 00:00:00 2001
|
|
From: David Marlin <dmarlin@redhat.com>
|
|
Date: Wed, 15 Apr 2026 17:00:08 -0500
|
|
Subject: [PATCH] Bluetooth: ISO: Add support to bind to trigger PAST
|
|
|
|
JIRA: https://issues.redhat.com/browse/RHEL-157827
|
|
|
|
commit d3413703d5f8b7d1e6f514f9440ed5da1bc30796
|
|
Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
|
Date: Fri Sep 5 11:34:44 2025 -0400
|
|
|
|
Bluetooth: ISO: Add support to bind to trigger PAST
|
|
|
|
This makes it possible to bind to a different destination address
|
|
after being connected (BT_CONNECTED, BT_CONNECT2) which then triggers
|
|
PAST Sender proceedure to transfer the PA Sync to the destination
|
|
address.
|
|
|
|
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
|
|
|
Conflicts:
|
|
Context difference due to missing network commit:
|
|
commit 0e50474fa514 net: Convert proto_ops bind() callbacks to use sockaddr_unsized
|
|
|
|
Signed-off-by: David Marlin <dmarlin@redhat.com>
|
|
|
|
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
|
|
index 8c2235444808..1f74722f3f4d 100644
|
|
--- a/include/net/bluetooth/hci_core.h
|
|
+++ b/include/net/bluetooth/hci_core.h
|
|
@@ -1602,6 +1602,7 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
|
struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid,
|
|
struct bt_iso_qos *qos,
|
|
__u8 base_len, __u8 *base, u16 timeout);
|
|
+int hci_past_bis(struct hci_conn *conn, bdaddr_t *dst, __u8 dst_type);
|
|
struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
|
__u8 dst_type, struct bt_iso_qos *qos,
|
|
u16 timeout);
|
|
diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h
|
|
index e352a4e0ef8d..3133f40fa9f9 100644
|
|
--- a/include/net/bluetooth/hci_sync.h
|
|
+++ b/include/net/bluetooth/hci_sync.h
|
|
@@ -188,3 +188,4 @@ int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
|
|
|
|
int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn);
|
|
int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn);
|
|
+int hci_past_sync(struct hci_conn *conn, struct hci_conn *le);
|
|
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
|
|
index 6fc0692abf05..4f9dc1435ccc 100644
|
|
--- a/net/bluetooth/hci_conn.c
|
|
+++ b/net/bluetooth/hci_conn.c
|
|
@@ -2245,6 +2245,18 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid,
|
|
return conn;
|
|
}
|
|
|
|
+int hci_past_bis(struct hci_conn *conn, bdaddr_t *dst, __u8 dst_type)
|
|
+{
|
|
+ struct hci_conn *le;
|
|
+
|
|
+ /* Lookup existing LE connection to rebind to */
|
|
+ le = hci_conn_hash_lookup_le(conn->hdev, dst, dst_type);
|
|
+ if (!le)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return hci_past_sync(conn, le);
|
|
+}
|
|
+
|
|
static void bis_mark_per_adv(struct hci_conn *conn, void *data)
|
|
{
|
|
struct iso_list_data *d = data;
|
|
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
|
|
index cb573b88505f..13d34c97b4d3 100644
|
|
--- a/net/bluetooth/hci_sync.c
|
|
+++ b/net/bluetooth/hci_sync.c
|
|
@@ -7229,3 +7229,95 @@ int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn)
|
|
return hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
|
|
create_big_complete);
|
|
}
|
|
+
|
|
+struct past_data {
|
|
+ struct hci_conn *conn;
|
|
+ struct hci_conn *le;
|
|
+};
|
|
+
|
|
+static void past_complete(struct hci_dev *hdev, void *data, int err)
|
|
+{
|
|
+ struct past_data *past = data;
|
|
+
|
|
+ bt_dev_dbg(hdev, "err %d", err);
|
|
+
|
|
+ kfree(past);
|
|
+}
|
|
+
|
|
+static int hci_le_past_set_info_sync(struct hci_dev *hdev, void *data)
|
|
+{
|
|
+ struct past_data *past = data;
|
|
+ struct hci_cp_le_past_set_info cp;
|
|
+
|
|
+ hci_dev_lock(hdev);
|
|
+
|
|
+ if (!hci_conn_valid(hdev, past->conn) ||
|
|
+ !hci_conn_valid(hdev, past->le)) {
|
|
+ hci_dev_unlock(hdev);
|
|
+ return -ECANCELED;
|
|
+ }
|
|
+
|
|
+ memset(&cp, 0, sizeof(cp));
|
|
+ cp.handle = cpu_to_le16(past->le->handle);
|
|
+ cp.adv_handle = past->conn->iso_qos.bcast.bis;
|
|
+
|
|
+ hci_dev_unlock(hdev);
|
|
+
|
|
+ return __hci_cmd_sync_status(hdev, HCI_OP_LE_PAST_SET_INFO,
|
|
+ sizeof(cp), &cp, HCI_CMD_TIMEOUT);
|
|
+}
|
|
+
|
|
+static int hci_le_past_sync(struct hci_dev *hdev, void *data)
|
|
+{
|
|
+ struct past_data *past = data;
|
|
+ struct hci_cp_le_past cp;
|
|
+
|
|
+ hci_dev_lock(hdev);
|
|
+
|
|
+ if (!hci_conn_valid(hdev, past->conn) ||
|
|
+ !hci_conn_valid(hdev, past->le)) {
|
|
+ hci_dev_unlock(hdev);
|
|
+ return -ECANCELED;
|
|
+ }
|
|
+
|
|
+ memset(&cp, 0, sizeof(cp));
|
|
+ cp.handle = cpu_to_le16(past->le->handle);
|
|
+ cp.sync_handle = cpu_to_le16(past->conn->sync_handle);
|
|
+
|
|
+ hci_dev_unlock(hdev);
|
|
+
|
|
+ return __hci_cmd_sync_status(hdev, HCI_OP_LE_PAST,
|
|
+ sizeof(cp), &cp, HCI_CMD_TIMEOUT);
|
|
+}
|
|
+
|
|
+int hci_past_sync(struct hci_conn *conn, struct hci_conn *le)
|
|
+{
|
|
+ struct past_data *data;
|
|
+ int err;
|
|
+
|
|
+ if (conn->type != BIS_LINK && conn->type != PA_LINK)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!past_sender_capable(conn->hdev))
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
|
|
+ if (!data)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ data->conn = conn;
|
|
+ data->le = le;
|
|
+
|
|
+ if (conn->role == HCI_ROLE_MASTER)
|
|
+ err = hci_cmd_sync_queue_once(conn->hdev,
|
|
+ hci_le_past_set_info_sync, data,
|
|
+ past_complete);
|
|
+ else
|
|
+ err = hci_cmd_sync_queue_once(conn->hdev, hci_le_past_sync,
|
|
+ data, past_complete);
|
|
+
|
|
+ if (err)
|
|
+ kfree(data);
|
|
+
|
|
+ return err;
|
|
+}
|
|
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
|
|
index 3c568d3d8ac9..607172b35267 100644
|
|
--- a/net/bluetooth/iso.c
|
|
+++ b/net/bluetooth/iso.c
|
|
@@ -987,20 +987,14 @@ static int iso_sock_bind_bc(struct socket *sock, struct sockaddr *addr,
|
|
return 0;
|
|
}
|
|
|
|
-static int iso_sock_bind_pa_sk(struct sock *sk, struct sockaddr_iso *sa,
|
|
+/* Must be called on the locked socket. */
|
|
+static int iso_sock_rebind_bis(struct sock *sk, struct sockaddr_iso *sa,
|
|
int addr_len)
|
|
{
|
|
int err = 0;
|
|
|
|
- if (sk->sk_type != SOCK_SEQPACKET) {
|
|
- err = -EINVAL;
|
|
- goto done;
|
|
- }
|
|
-
|
|
- if (addr_len != sizeof(*sa) + sizeof(*sa->iso_bc)) {
|
|
- err = -EINVAL;
|
|
- goto done;
|
|
- }
|
|
+ if (!test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags))
|
|
+ return -EBADFD;
|
|
|
|
if (sa->iso_bc->bc_num_bis > ISO_MAX_NUM_BIS) {
|
|
err = -EINVAL;
|
|
@@ -1023,6 +1017,77 @@ static int iso_sock_bind_pa_sk(struct sock *sk, struct sockaddr_iso *sa,
|
|
return err;
|
|
}
|
|
|
|
+static struct hci_dev *iso_conn_get_hdev(struct iso_conn *conn)
|
|
+{
|
|
+ struct hci_dev *hdev = NULL;
|
|
+
|
|
+ iso_conn_lock(conn);
|
|
+ if (conn->hcon)
|
|
+ hdev = hci_dev_hold(conn->hcon->hdev);
|
|
+ iso_conn_unlock(conn);
|
|
+
|
|
+ return hdev;
|
|
+}
|
|
+
|
|
+/* Must be called on the locked socket. */
|
|
+static int iso_sock_rebind_bc(struct sock *sk, struct sockaddr_iso *sa,
|
|
+ int addr_len)
|
|
+{
|
|
+ struct hci_dev *hdev;
|
|
+ struct hci_conn *bis;
|
|
+ int err;
|
|
+
|
|
+ if (sk->sk_type != SOCK_SEQPACKET || !iso_pi(sk)->conn)
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* Check if it is really a Broadcast address being requested */
|
|
+ if (addr_len != sizeof(*sa) + sizeof(*sa->iso_bc))
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* Check if the address hasn't changed then perhaps only the number of
|
|
+ * bis has changed.
|
|
+ */
|
|
+ if (!bacmp(&iso_pi(sk)->dst, &sa->iso_bc->bc_bdaddr) ||
|
|
+ !bacmp(&sa->iso_bc->bc_bdaddr, BDADDR_ANY))
|
|
+ return iso_sock_rebind_bis(sk, sa, addr_len);
|
|
+
|
|
+ /* Check if the address type is of LE type */
|
|
+ if (!bdaddr_type_is_le(sa->iso_bc->bc_bdaddr_type))
|
|
+ return -EINVAL;
|
|
+
|
|
+ hdev = iso_conn_get_hdev(iso_pi(sk)->conn);
|
|
+ if (!hdev)
|
|
+ return -EINVAL;
|
|
+
|
|
+ bis = iso_pi(sk)->conn->hcon;
|
|
+
|
|
+ /* Release the socket before lookups since that requires hci_dev_lock
|
|
+ * which shall not be acquired while holding sock_lock for proper
|
|
+ * ordering.
|
|
+ */
|
|
+ release_sock(sk);
|
|
+ hci_dev_lock(bis->hdev);
|
|
+ lock_sock(sk);
|
|
+
|
|
+ if (!iso_pi(sk)->conn || iso_pi(sk)->conn->hcon != bis) {
|
|
+ /* raced with iso_conn_del() or iso_disconn_sock() */
|
|
+ err = -ENOTCONN;
|
|
+ goto unlock;
|
|
+ }
|
|
+
|
|
+ BT_DBG("sk %p %pMR type %u", sk, &sa->iso_bc->bc_bdaddr,
|
|
+ sa->iso_bc->bc_bdaddr_type);
|
|
+
|
|
+ err = hci_past_bis(bis, &sa->iso_bc->bc_bdaddr,
|
|
+ le_addr_type(sa->iso_bc->bc_bdaddr_type));
|
|
+
|
|
+unlock:
|
|
+ hci_dev_unlock(hdev);
|
|
+ hci_dev_put(hdev);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
static int iso_sock_bind(struct socket *sock, struct sockaddr *addr,
|
|
int addr_len)
|
|
{
|
|
@@ -1038,13 +1103,12 @@ static int iso_sock_bind(struct socket *sock, struct sockaddr *addr,
|
|
|
|
lock_sock(sk);
|
|
|
|
- /* Allow the user to bind a PA sync socket to a number
|
|
- * of BISes to sync to.
|
|
- */
|
|
- if ((sk->sk_state == BT_CONNECT2 ||
|
|
- sk->sk_state == BT_CONNECTED) &&
|
|
- test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
|
|
- err = iso_sock_bind_pa_sk(sk, sa, addr_len);
|
|
+ if ((sk->sk_state == BT_CONNECT2 || sk->sk_state == BT_CONNECTED) &&
|
|
+ addr_len > sizeof(*sa)) {
|
|
+ /* Allow the user to rebind to a different address using
|
|
+ * PAST procedures.
|
|
+ */
|
|
+ err = iso_sock_rebind_bc(sk, sa, addr_len);
|
|
goto done;
|
|
}
|
|
|
|
--
|
|
2.50.1 (Apple Git-155)
|
|
|