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.
356 lines
11 KiB
Diff
356 lines
11 KiB
Diff
From c33ae38cff3d15c40384b4ecbaccc4c88d3cb741 Mon Sep 17 00:00:00 2001
|
|
From: David Marlin <dmarlin@redhat.com>
|
|
Date: Wed, 15 Apr 2026 16:59:13 -0500
|
|
Subject: [PATCH] Bluetooth: HCI: Add initial support for PAST
|
|
|
|
JIRA: https://issues.redhat.com/browse/RHEL-157827
|
|
|
|
commit 33b2835f0b7e2a458473b0e3a23b54b92108b6b0
|
|
Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
|
Date: Tue Sep 2 11:11:40 2025 -0400
|
|
|
|
Bluetooth: HCI: Add initial support for PAST
|
|
|
|
This adds PAST related commands (HCI_OP_LE_PAST,
|
|
HCI_OP_LE_PAST_SET_INFO and HCI_OP_LE_PAST_PARAMS) and events
|
|
(HCI_EV_LE_PAST_RECEIVED) along with handling of PAST sender and
|
|
receiver features bits including new MGMG settings (
|
|
HCI_EV_LE_PAST_RECEIVED and MGMT_SETTING_PAST_RECEIVER) which
|
|
userspace can use to determine if PAST is supported by the
|
|
controller.
|
|
|
|
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
|
|
|
|
Signed-off-by: David Marlin <dmarlin@redhat.com>
|
|
|
|
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
|
|
index cb4c02d00759..d883ad233ebc 100644
|
|
--- a/include/net/bluetooth/hci.h
|
|
+++ b/include/net/bluetooth/hci.h
|
|
@@ -647,6 +647,8 @@ enum {
|
|
#define HCI_LE_EXT_ADV 0x10
|
|
#define HCI_LE_PERIODIC_ADV 0x20
|
|
#define HCI_LE_CHAN_SEL_ALG2 0x40
|
|
+#define HCI_LE_PAST_SENDER 0x01
|
|
+#define HCI_LE_PAST_RECEIVER 0x02
|
|
#define HCI_LE_CIS_CENTRAL 0x10
|
|
#define HCI_LE_CIS_PERIPHERAL 0x20
|
|
#define HCI_LE_ISO_BROADCASTER 0x40
|
|
@@ -2068,6 +2070,44 @@ struct hci_cp_le_set_privacy_mode {
|
|
__u8 mode;
|
|
} __packed;
|
|
|
|
+#define HCI_OP_LE_PAST 0x205a
|
|
+struct hci_cp_le_past {
|
|
+ __le16 handle;
|
|
+ __le16 service_data;
|
|
+ __le16 sync_handle;
|
|
+} __packed;
|
|
+
|
|
+struct hci_rp_le_past {
|
|
+ __u8 status;
|
|
+ __le16 handle;
|
|
+} __packed;
|
|
+
|
|
+#define HCI_OP_LE_PAST_SET_INFO 0x205b
|
|
+struct hci_cp_le_past_set_info {
|
|
+ __le16 handle;
|
|
+ __le16 service_data;
|
|
+ __u8 adv_handle;
|
|
+} __packed;
|
|
+
|
|
+struct hci_rp_le_past_set_info {
|
|
+ __u8 status;
|
|
+ __le16 handle;
|
|
+} __packed;
|
|
+
|
|
+#define HCI_OP_LE_PAST_PARAMS 0x205c
|
|
+struct hci_cp_le_past_params {
|
|
+ __le16 handle;
|
|
+ __u8 mode;
|
|
+ __le16 skip;
|
|
+ __le16 sync_timeout;
|
|
+ __u8 cte_type;
|
|
+} __packed;
|
|
+
|
|
+struct hci_rp_le_past_params {
|
|
+ __u8 status;
|
|
+ __le16 handle;
|
|
+} __packed;
|
|
+
|
|
#define HCI_OP_LE_READ_BUFFER_SIZE_V2 0x2060
|
|
struct hci_rp_le_read_buffer_size_v2 {
|
|
__u8 status;
|
|
@@ -2800,6 +2840,20 @@ struct hci_evt_le_ext_adv_set_term {
|
|
__u8 num_evts;
|
|
} __packed;
|
|
|
|
+#define HCI_EV_LE_PAST_RECEIVED 0x18
|
|
+struct hci_ev_le_past_received {
|
|
+ __u8 status;
|
|
+ __le16 handle;
|
|
+ __le16 service_data;
|
|
+ __le16 sync_handle;
|
|
+ __u8 sid;
|
|
+ __u8 bdaddr_type;
|
|
+ bdaddr_t bdaddr;
|
|
+ __u8 phy;
|
|
+ __le16 interval;
|
|
+ __u8 clock_accuracy;
|
|
+} __packed;
|
|
+
|
|
#define HCI_EVT_LE_CIS_ESTABLISHED 0x19
|
|
struct hci_evt_le_cis_established {
|
|
__u8 status;
|
|
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
|
|
index 0cb87687837f..1bd12c303e25 100644
|
|
--- a/include/net/bluetooth/hci_core.h
|
|
+++ b/include/net/bluetooth/hci_core.h
|
|
@@ -2053,6 +2053,18 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
|
#define sync_recv_capable(dev) \
|
|
((dev)->le_features[3] & HCI_LE_ISO_SYNC_RECEIVER)
|
|
#define sync_recv_enabled(dev) (le_enabled(dev) && sync_recv_capable(dev))
|
|
+#define past_sender_capable(dev) \
|
|
+ ((dev)->le_features[3] & HCI_LE_PAST_SENDER)
|
|
+#define past_receiver_capable(dev) \
|
|
+ ((dev)->le_features[3] & HCI_LE_PAST_RECEIVER)
|
|
+#define past_capable(dev) \
|
|
+ (past_sender_capable(dev) || past_receiver_capable(dev))
|
|
+#define past_sender_enabled(dev) \
|
|
+ (le_enabled(dev) && past_sender_capable(dev))
|
|
+#define past_receiver_enabled(dev) \
|
|
+ (le_enabled(dev) && past_receiver_capable(dev))
|
|
+#define past_enabled(dev) \
|
|
+ (past_sender_enabled(dev) || past_receiver_enabled(dev))
|
|
|
|
#define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \
|
|
(!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG)))
|
|
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
|
|
index f5be96f08b9d..8234915854b6 100644
|
|
--- a/include/net/bluetooth/mgmt.h
|
|
+++ b/include/net/bluetooth/mgmt.h
|
|
@@ -119,6 +119,8 @@ struct mgmt_rp_read_index_list {
|
|
#define MGMT_SETTING_ISO_BROADCASTER BIT(20)
|
|
#define MGMT_SETTING_ISO_SYNC_RECEIVER BIT(21)
|
|
#define MGMT_SETTING_LL_PRIVACY BIT(22)
|
|
+#define MGMT_SETTING_PAST_SENDER BIT(23)
|
|
+#define MGMT_SETTING_PAST_RECEIVER BIT(24)
|
|
|
|
#define MGMT_OP_READ_INFO 0x0004
|
|
#define MGMT_READ_INFO_SIZE 0
|
|
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
|
|
index 3838b90343d9..af34c9938509 100644
|
|
--- a/net/bluetooth/hci_event.c
|
|
+++ b/net/bluetooth/hci_event.c
|
|
@@ -5936,6 +5936,71 @@ static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, void *data,
|
|
hci_dev_unlock(hdev);
|
|
}
|
|
|
|
+static int hci_le_pa_term_sync(struct hci_dev *hdev, __le16 handle)
|
|
+{
|
|
+ struct hci_cp_le_pa_term_sync cp;
|
|
+
|
|
+ memset(&cp, 0, sizeof(cp));
|
|
+ cp.handle = handle;
|
|
+
|
|
+ return hci_send_cmd(hdev, HCI_OP_LE_PA_TERM_SYNC, sizeof(cp), &cp);
|
|
+}
|
|
+
|
|
+static void hci_le_past_received_evt(struct hci_dev *hdev, void *data,
|
|
+ struct sk_buff *skb)
|
|
+{
|
|
+ struct hci_ev_le_past_received *ev = data;
|
|
+ int mask = hdev->link_mode;
|
|
+ __u8 flags = 0;
|
|
+ struct hci_conn *pa_sync, *conn;
|
|
+
|
|
+ bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
|
+
|
|
+ hci_dev_lock(hdev);
|
|
+
|
|
+ hci_dev_clear_flag(hdev, HCI_PA_SYNC);
|
|
+
|
|
+ conn = hci_conn_hash_lookup_create_pa_sync(hdev);
|
|
+ if (!conn) {
|
|
+ bt_dev_err(hdev,
|
|
+ "Unable to find connection for dst %pMR sid 0x%2.2x",
|
|
+ &ev->bdaddr, ev->sid);
|
|
+ goto unlock;
|
|
+ }
|
|
+
|
|
+ conn->sync_handle = le16_to_cpu(ev->sync_handle);
|
|
+ conn->sid = HCI_SID_INVALID;
|
|
+
|
|
+ mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, PA_LINK,
|
|
+ &flags);
|
|
+ if (!(mask & HCI_LM_ACCEPT)) {
|
|
+ hci_le_pa_term_sync(hdev, ev->sync_handle);
|
|
+ goto unlock;
|
|
+ }
|
|
+
|
|
+ if (!(flags & HCI_PROTO_DEFER))
|
|
+ goto unlock;
|
|
+
|
|
+ /* Add connection to indicate PA sync event */
|
|
+ pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY,
|
|
+ HCI_ROLE_SLAVE);
|
|
+
|
|
+ if (IS_ERR(pa_sync))
|
|
+ goto unlock;
|
|
+
|
|
+ pa_sync->sync_handle = le16_to_cpu(ev->sync_handle);
|
|
+
|
|
+ if (ev->status) {
|
|
+ set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags);
|
|
+
|
|
+ /* Notify iso layer */
|
|
+ hci_connect_cfm(pa_sync, ev->status);
|
|
+ }
|
|
+
|
|
+unlock:
|
|
+ hci_dev_unlock(hdev);
|
|
+}
|
|
+
|
|
static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, void *data,
|
|
struct sk_buff *skb)
|
|
{
|
|
@@ -6412,16 +6477,6 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, void *data,
|
|
hci_dev_unlock(hdev);
|
|
}
|
|
|
|
-static int hci_le_pa_term_sync(struct hci_dev *hdev, __le16 handle)
|
|
-{
|
|
- struct hci_cp_le_pa_term_sync cp;
|
|
-
|
|
- memset(&cp, 0, sizeof(cp));
|
|
- cp.handle = handle;
|
|
-
|
|
- return hci_send_cmd(hdev, HCI_OP_LE_PA_TERM_SYNC, sizeof(cp), &cp);
|
|
-}
|
|
-
|
|
static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data,
|
|
struct sk_buff *skb)
|
|
{
|
|
@@ -7206,6 +7261,10 @@ static const struct hci_le_ev {
|
|
/* [0x12 = HCI_EV_LE_EXT_ADV_SET_TERM] */
|
|
HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt,
|
|
sizeof(struct hci_evt_le_ext_adv_set_term)),
|
|
+ /* [0x18 = HCI_EVT_LE_PAST_RECEIVED] */
|
|
+ HCI_LE_EV(HCI_EV_LE_PAST_RECEIVED,
|
|
+ hci_le_past_received_evt,
|
|
+ sizeof(struct hci_ev_le_past_received)),
|
|
/* [0x19 = HCI_EVT_LE_CIS_ESTABLISHED] */
|
|
HCI_LE_EV(HCI_EVT_LE_CIS_ESTABLISHED, hci_le_cis_established_evt,
|
|
sizeof(struct hci_evt_le_cis_established)),
|
|
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
|
|
index e302afc781a5..d181c89a7b0e 100644
|
|
--- a/net/bluetooth/hci_sync.c
|
|
+++ b/net/bluetooth/hci_sync.c
|
|
@@ -4393,6 +4393,9 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
|
|
if (ext_adv_capable(hdev))
|
|
events[2] |= 0x02; /* LE Advertising Set Terminated */
|
|
|
|
+ if (past_receiver_capable(hdev))
|
|
+ events[2] |= 0x80; /* LE PAST Received */
|
|
+
|
|
if (cis_capable(hdev)) {
|
|
events[3] |= 0x01; /* LE CIS Established */
|
|
if (cis_peripheral_capable(hdev))
|
|
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
|
|
index c0ae6c6fbe94..3c568d3d8ac9 100644
|
|
--- a/net/bluetooth/iso.c
|
|
+++ b/net/bluetooth/iso.c
|
|
@@ -80,6 +80,7 @@ static struct bt_iso_qos default_qos;
|
|
static bool check_ucast_qos(struct bt_iso_qos *qos);
|
|
static bool check_bcast_qos(struct bt_iso_qos *qos);
|
|
static bool iso_match_sid(struct sock *sk, void *data);
|
|
+static bool iso_match_sid_past(struct sock *sk, void *data);
|
|
static bool iso_match_sync_handle(struct sock *sk, void *data);
|
|
static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data);
|
|
static void iso_sock_disconn(struct sock *sk);
|
|
@@ -2090,6 +2091,16 @@ static bool iso_match_sid(struct sock *sk, void *data)
|
|
return ev->sid == iso_pi(sk)->bc_sid;
|
|
}
|
|
|
|
+static bool iso_match_sid_past(struct sock *sk, void *data)
|
|
+{
|
|
+ struct hci_ev_le_past_received *ev = data;
|
|
+
|
|
+ if (iso_pi(sk)->bc_sid == HCI_SID_INVALID)
|
|
+ return true;
|
|
+
|
|
+ return ev->sid == iso_pi(sk)->bc_sid;
|
|
+}
|
|
+
|
|
static bool iso_match_sync_handle(struct sock *sk, void *data)
|
|
{
|
|
struct hci_evt_le_big_info_adv_report *ev = data;
|
|
@@ -2109,6 +2120,7 @@ static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data)
|
|
int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|
{
|
|
struct hci_ev_le_pa_sync_established *ev1;
|
|
+ struct hci_ev_le_past_received *ev1a;
|
|
struct hci_evt_le_big_info_adv_report *ev2;
|
|
struct hci_ev_le_per_adv_report *ev3;
|
|
struct sock *sk;
|
|
@@ -2122,6 +2134,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|
* SID to listen to and once sync is established its handle needs to
|
|
* be stored in iso_pi(sk)->sync_handle so it can be matched once
|
|
* receiving the BIG Info.
|
|
+ * 1a. HCI_EV_LE_PAST_RECEIVED: alternative to 1.
|
|
* 2. HCI_EVT_LE_BIG_INFO_ADV_REPORT: When connect_ind is triggered by a
|
|
* a BIG Info it attempts to check if there any listening socket with
|
|
* the same sync_handle and if it does then attempt to create a sync.
|
|
@@ -2141,6 +2154,18 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|
goto done;
|
|
}
|
|
|
|
+ ev1a = hci_recv_event_data(hdev, HCI_EV_LE_PAST_RECEIVED);
|
|
+ if (ev1a) {
|
|
+ sk = iso_get_sock(&hdev->bdaddr, bdaddr, BT_LISTEN,
|
|
+ iso_match_sid_past, ev1a);
|
|
+ if (sk && !ev1a->status) {
|
|
+ iso_pi(sk)->sync_handle = le16_to_cpu(ev1a->sync_handle);
|
|
+ iso_pi(sk)->bc_sid = ev1a->sid;
|
|
+ }
|
|
+
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
ev2 = hci_recv_event_data(hdev, HCI_EVT_LE_BIG_INFO_ADV_REPORT);
|
|
if (ev2) {
|
|
/* Check if BIGInfo report has already been handled */
|
|
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
|
|
index 6fd13a39f48a..7cca24f6ef49 100644
|
|
--- a/net/bluetooth/mgmt.c
|
|
+++ b/net/bluetooth/mgmt.c
|
|
@@ -852,6 +852,12 @@ static u32 get_supported_settings(struct hci_dev *hdev)
|
|
if (ll_privacy_capable(hdev))
|
|
settings |= MGMT_SETTING_LL_PRIVACY;
|
|
|
|
+ if (past_sender_capable(hdev))
|
|
+ settings |= MGMT_SETTING_PAST_SENDER;
|
|
+
|
|
+ if (past_receiver_capable(hdev))
|
|
+ settings |= MGMT_SETTING_PAST_RECEIVER;
|
|
+
|
|
settings |= MGMT_SETTING_PHY_CONFIGURATION;
|
|
|
|
return settings;
|
|
@@ -937,6 +943,12 @@ static u32 get_current_settings(struct hci_dev *hdev)
|
|
if (ll_privacy_enabled(hdev))
|
|
settings |= MGMT_SETTING_LL_PRIVACY;
|
|
|
|
+ if (past_sender_enabled(hdev))
|
|
+ settings |= MGMT_SETTING_PAST_SENDER;
|
|
+
|
|
+ if (past_receiver_enabled(hdev))
|
|
+ settings |= MGMT_SETTING_PAST_RECEIVER;
|
|
+
|
|
return settings;
|
|
}
|
|
|
|
--
|
|
2.50.1 (Apple Git-155)
|
|
|