* [PATCH v1 1/3] Bluetooth: Add support for Shorter Connection Interval (SCI) feature
@ 2026-07-24 16:35 Luiz Augusto von Dentz
2026-07-24 16:35 ` [PATCH v1 2/3] Bluetooth: Add MGMT Shorter Connection Interval setting Luiz Augusto von Dentz
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Luiz Augusto von Dentz @ 2026-07-24 16:35 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Add HCI command, event and feature bit definitions for the Bluetooth
6.2 Shorter Connection Interval feature:
Commands:
- HCI_OP_LE_CONN_RATE (0x20a1) - Connection Rate Request
- HCI_OP_LE_SET_DEF_RATE (0x20a2) - Set Default Rate Parameters
- HCI_OP_LE_READ_CONN_INTERVAL (0x20a3) - Read Min Supported
Connection Interval
Events:
- HCI_EVT_LE_CONN_RATE_CHANGE (0x37) - Connection Rate Change
Feature bits:
- HCI_LE_SCI - Shorter Connection Intervals
- HCI_LE_SCI_HOST - Shorter Connection Intervals (Host Support)
During controller init, when SCI is supported:
- Set Shorter Connection Intervals (Host Support) feature via
LE Set Host Feature
- Read Minimum Supported Connection Interval
- Set Default Rate Parameters
The Connection Rate Change event handler updates the connection
interval, latency and supervision timeout on the hci_conn.
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
include/net/bluetooth/hci.h | 53 ++++++++++++++++++++++++++++++++
include/net/bluetooth/hci_core.h | 3 ++
net/bluetooth/hci_event.c | 27 ++++++++++++++++
net/bluetooth/hci_sync.c | 46 +++++++++++++++++++++++++++
4 files changed, 129 insertions(+)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 50f0eef71fb1..f895278c268f 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -653,6 +653,8 @@ enum {
#define HCI_LE_LL_EXT_FEATURE 0x80
#define HCI_LE_CS 0x40
#define HCI_LE_CS_HOST 0x80
+#define HCI_LE_SCI 0x01 /* byte 9 - Shorter Connection Intervals */
+#define HCI_LE_SCI_HOST 0x02 /* byte 9 - Shorter Connection Intervals (Host) */
/* Connection modes */
#define HCI_CM_ACTIVE 0x0000
@@ -2489,6 +2491,46 @@ struct hci_cp_le_set_host_feature_v2 {
__u8 bit_value;
} __packed;
+#define HCI_OP_LE_CONN_RATE 0x20a1
+struct hci_cp_le_conn_rate {
+ __le16 handle;
+ __le16 interval_min;
+ __le16 interval_max;
+ __le16 subrate_min;
+ __le16 subrate_max;
+ __le16 max_latency;
+ __le16 cont_num;
+ __le16 supv_timeout;
+ __le16 min_ce_len;
+ __le16 max_ce_len;
+} __packed;
+
+#define HCI_OP_LE_SET_DEF_RATE 0x20a2
+struct hci_cp_le_set_def_rate {
+ __le16 interval_min;
+ __le16 interval_max;
+ __le16 subrate_min;
+ __le16 subrate_max;
+ __le16 max_latency;
+ __le16 cont_num;
+ __le16 supv_timeout;
+ __le16 min_ce_len;
+ __le16 max_ce_len;
+} __packed;
+
+#define HCI_OP_LE_READ_CONN_INTERVAL 0x20a3
+struct hci_le_conn_interval_group {
+ __le16 min;
+ __le16 max;
+ __le16 stride;
+} __packed;
+
+struct hci_rp_le_read_conn_interval {
+ __u8 status;
+ __u8 num_grps;
+ struct hci_le_conn_interval_group grps[];
+} __packed;
+
/* ---- HCI Events ---- */
struct hci_ev_status {
__u8 status;
@@ -3303,6 +3345,17 @@ struct hci_evt_le_cs_test_end_complete {
__u8 status;
} __packed;
+#define HCI_EVT_LE_CONN_RATE_CHANGE 0x37
+struct hci_evt_le_conn_rate_change {
+ __u8 status;
+ __le16 handle;
+ __le16 interval;
+ __le16 subrate;
+ __le16 latency;
+ __le16 cont_number;
+ __le16 supv_timeout;
+} __packed;
+
#define HCI_EV_VENDOR 0xff
/* Internal events generated by Bluetooth stack */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e7133ff87fbf..7e58acb65f48 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -2077,6 +2077,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define le_cs_host_capable(dev) \
((dev)->le_features[5] & HCI_LE_CS_HOST)
+#define le_sci_capable(dev) \
+ ((dev)->le_features[9] & HCI_LE_SCI)
+
#define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \
(!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG)))
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index ea858391c789..a2da7876b6b4 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -7363,6 +7363,29 @@ static void hci_le_read_all_remote_features_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev);
}
+static void hci_le_conn_rate_change_evt(struct hci_dev *hdev, void *data,
+ struct sk_buff *skb)
+{
+ struct hci_evt_le_conn_rate_change *ev = data;
+ struct hci_conn *conn;
+
+ bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
+
+ if (ev->status)
+ return;
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+ if (conn) {
+ conn->le_conn_interval = le16_to_cpu(ev->interval);
+ conn->le_conn_latency = le16_to_cpu(ev->latency);
+ conn->le_supv_timeout = le16_to_cpu(ev->supv_timeout);
+ }
+
+ hci_dev_unlock(hdev);
+}
+
#define HCI_LE_EV_VL(_op, _func, _min_len, _max_len) \
[_op] = { \
.func = _func, \
@@ -7474,6 +7497,10 @@ static const struct hci_le_ev {
sizeof(struct
hci_evt_le_read_all_remote_features_complete),
HCI_MAX_EVENT_SIZE),
+ /* [0x37 = HCI_EVT_LE_CONN_RATE_CHANGE] */
+ HCI_LE_EV(HCI_EVT_LE_CONN_RATE_CHANGE,
+ hci_le_conn_rate_change_evt,
+ sizeof(struct hci_evt_le_conn_rate_change)),
};
static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 7a33513f1fc7..cd3e39c8bb86 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -4478,6 +4478,10 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
events[6] |= 0x02; /* LE CS Subevent Result Continue event */
events[6] |= 0x04; /* LE CS Test End Complete event */
}
+
+ if (le_sci_capable(hdev))
+ events[6] |= 0x40; /* LE Connection Rate Change event */
+
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EVENT_MASK,
sizeof(events), events, HCI_CMD_TIMEOUT);
}
@@ -4646,6 +4650,40 @@ static int hci_le_set_host_feature_sync(struct hci_dev *hdev, u16 bit, u8 value)
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
+static int hci_le_read_conn_interval_sync(struct hci_dev *hdev)
+{
+ if (!le_sci_capable(hdev))
+ return 0;
+
+ return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_CONN_INTERVAL,
+ 0, NULL, HCI_CMD_TIMEOUT);
+}
+
+static int hci_le_set_def_rate_sync(struct hci_dev *hdev)
+{
+ struct hci_cp_le_set_def_rate cp;
+
+ if (!le_sci_capable(hdev))
+ return 0;
+
+ memset(&cp, 0, sizeof(cp));
+
+ /* Use the HIDS 1.2 recommended Full Range mode values as the default
+ * rate parameters (see HOGP v1.2 spec). Connection intervals are in
+ * units of 0.125 ms and the supervision timeout is in units of 10 ms.
+ */
+ cp.interval_min = cpu_to_le16(0x000a); /* 1.25 ms */
+ cp.interval_max = cpu_to_le16(0x0078); /* 15 ms */
+ cp.subrate_min = cpu_to_le16(0x0001);
+ cp.subrate_max = cpu_to_le16(0x0004);
+ cp.max_latency = cpu_to_le16(0x0000);
+ cp.cont_num = cpu_to_le16(0x0001);
+ cp.supv_timeout = cpu_to_le16(0x000c); /* 120 ms */
+
+ return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_DEF_RATE,
+ sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
/* Set Host Features, each feature needs to be sent separately since
* HCI_OP_LE_SET_HOST_FEATURE doesn't support setting all of them at once.
*/
@@ -4666,6 +4704,10 @@ static int hci_le_set_host_features_sync(struct hci_dev *hdev)
/* Channel Sounding (Host Support) */
err = hci_le_set_host_feature_sync(hdev, 47, 0x01);
+ if (le_sci_capable(hdev))
+ /* Shorter Connection Intervals (Host Support) */
+ err = hci_le_set_host_feature_sync(hdev, 73, 0x01);
+
return err;
}
@@ -4697,6 +4739,10 @@ static const struct hci_init_stage le_init3[] = {
HCI_INIT(hci_set_le_support_sync),
/* HCI_OP_LE_SET_HOST_FEATURE */
HCI_INIT(hci_le_set_host_features_sync),
+ /* HCI_OP_LE_READ_CONN_INTERVAL */
+ HCI_INIT(hci_le_read_conn_interval_sync),
+ /* HCI_OP_LE_SET_DEF_RATE */
+ HCI_INIT(hci_le_set_def_rate_sync),
{}
};
--
2.54.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v1 2/3] Bluetooth: Add MGMT Shorter Connection Interval setting
2026-07-24 16:35 [PATCH v1 1/3] Bluetooth: Add support for Shorter Connection Interval (SCI) feature Luiz Augusto von Dentz
@ 2026-07-24 16:35 ` Luiz Augusto von Dentz
2026-07-24 16:35 ` [PATCH v1 3/3] Bluetooth: Add MGMT Load Connection Subrate command Luiz Augusto von Dentz
2026-07-24 17:59 ` [v1,1/3] Bluetooth: Add support for Shorter Connection Interval (SCI) feature bluez.test.bot
2 siblings, 0 replies; 4+ messages in thread
From: Luiz Augusto von Dentz @ 2026-07-24 16:35 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Add MGMT_SETTING_SCI (bit 25) to advertise support for the Shorter
Connection Interval (SCI) feature. It is reported in the supported
settings whenever the controller is SCI capable, and in the current
settings whenever LE is enabled and the controller is SCI capable
(SCI has no separate enable command, so it is a passive capability).
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
include/net/bluetooth/hci_core.h | 2 ++
include/net/bluetooth/mgmt.h | 1 +
net/bluetooth/mgmt.c | 6 ++++++
3 files changed, 9 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 7e58acb65f48..de0eb0ca5918 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -2079,6 +2079,8 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define le_sci_capable(dev) \
((dev)->le_features[9] & HCI_LE_SCI)
+#define le_sci_enabled(dev) \
+ (le_enabled(dev) && le_sci_capable(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 08daed7a96d5..b285441db55b 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -118,6 +118,7 @@ struct mgmt_rp_read_index_list {
#define MGMT_SETTING_LL_PRIVACY BIT(22)
#define MGMT_SETTING_PAST_SENDER BIT(23)
#define MGMT_SETTING_PAST_RECEIVER BIT(24)
+#define MGMT_SETTING_SCI BIT(25)
#define MGMT_OP_READ_INFO 0x0004
#define MGMT_READ_INFO_SIZE 0
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4fd37ac79986..58f01fbfcf71 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -861,6 +861,9 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (past_receiver_capable(hdev))
settings |= MGMT_SETTING_PAST_RECEIVER;
+ if (le_sci_capable(hdev))
+ settings |= MGMT_SETTING_SCI;
+
settings |= MGMT_SETTING_PHY_CONFIGURATION;
return settings;
@@ -952,6 +955,9 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (past_receiver_enabled(hdev))
settings |= MGMT_SETTING_PAST_RECEIVER;
+ if (le_sci_enabled(hdev))
+ settings |= MGMT_SETTING_SCI;
+
return settings;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v1 3/3] Bluetooth: Add MGMT Load Connection Subrate command
2026-07-24 16:35 [PATCH v1 1/3] Bluetooth: Add support for Shorter Connection Interval (SCI) feature Luiz Augusto von Dentz
2026-07-24 16:35 ` [PATCH v1 2/3] Bluetooth: Add MGMT Shorter Connection Interval setting Luiz Augusto von Dentz
@ 2026-07-24 16:35 ` Luiz Augusto von Dentz
2026-07-24 17:59 ` [v1,1/3] Bluetooth: Add support for Shorter Connection Interval (SCI) feature bluez.test.bot
2 siblings, 0 replies; 4+ messages in thread
From: Luiz Augusto von Dentz @ 2026-07-24 16:35 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Add MGMT_OP_LOAD_CONN_SUBRATE (0x005C) command to load per-device
connection subrate parameters when the SCI feature is supported.
Add MGMT_EV_CONN_SUBRATE (0x0033) event to notify userspace when
connection rate changes occur via the LE Connection Rate Change HCI
event.
Add subrate fields (subrate_min, subrate_max, max_latency, cont_num)
to struct hci_conn_params to store the loaded subrate parameters, and
the corresponding le_rate_* fields to struct hci_conn to track the
parameters currently in use.
When a single entry is loaded for an already-connected central, or on
connection completion, the LE Connection Rate Request procedure is
initiated to apply the parameters.
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
include/net/bluetooth/hci_core.h | 15 ++++
include/net/bluetooth/hci_sync.h | 4 ++
include/net/bluetooth/mgmt.h | 28 ++++++++
net/bluetooth/hci_event.c | 30 ++++++--
net/bluetooth/hci_sync.c | 40 +++++++++++
net/bluetooth/mgmt.c | 118 +++++++++++++++++++++++++++++++
6 files changed, 229 insertions(+), 6 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index de0eb0ca5918..a5ea461f45c9 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -720,6 +720,11 @@ struct hci_conn {
__u16 le_conn_interval;
__u16 le_conn_latency;
__u16 le_supv_timeout;
+ __u16 le_rate_interval;
+ __u16 le_subrate;
+ __u16 le_rate_latency;
+ __u16 le_cont_num;
+ __u16 le_rate_supv_timeout;
__u8 le_adv_data[HCI_MAX_EXT_AD_LENGTH];
__u8 le_adv_data_len;
__u8 le_per_adv_data[HCI_MAX_PER_AD_TOT_LEN];
@@ -810,6 +815,14 @@ struct hci_conn_params {
u16 conn_latency;
u16 supervision_timeout;
+ u16 rate_min_interval;
+ u16 rate_max_interval;
+ u16 subrate_min;
+ u16 subrate_max;
+ u16 max_latency;
+ u16 cont_num;
+ u16 rate_supv_timeout;
+
enum {
HCI_AUTO_CONN_DISABLED,
HCI_AUTO_CONN_REPORT,
@@ -2497,6 +2510,8 @@ void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
bdaddr_t *bdaddr, u8 addr_type);
+void mgmt_conn_subrate_notify(struct hci_dev *hdev, struct hci_conn *conn,
+ u8 status);
int hci_abort_conn(struct hci_conn *conn, u8 reason);
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h
index 0756d6fe77d4..53857aa29380 100644
--- a/include/net/bluetooth/hci_sync.h
+++ b/include/net/bluetooth/hci_sync.h
@@ -183,6 +183,10 @@ int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
struct hci_conn_params *params);
+int hci_le_conn_rate_sync(struct hci_dev *hdev, struct hci_conn *conn,
+ struct hci_conn_params *params);
+int hci_le_conn_rate_request(struct hci_dev *hdev,
+ struct hci_conn_params *params);
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);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index b285441db55b..1e22eab1081c 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -894,6 +894,23 @@ struct mgmt_cp_hci_cmd_sync {
} __packed;
#define MGMT_HCI_CMD_SYNC_SIZE 6
+#define MGMT_OP_LOAD_CONN_SUBRATE 0x005C
+struct mgmt_conn_subrate {
+ struct mgmt_addr_info addr;
+ __le16 min_interval;
+ __le16 max_interval;
+ __le16 subrate_min;
+ __le16 subrate_max;
+ __le16 max_latency;
+ __le16 cont_num;
+ __le16 supv_timeout;
+} __packed;
+struct mgmt_cp_load_conn_subrate {
+ __le16 param_count;
+ struct mgmt_conn_subrate params[] __counted_by_le(param_count);
+} __packed;
+#define MGMT_LOAD_CONN_SUBRATE_SIZE 2
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
@@ -1193,3 +1210,14 @@ struct mgmt_ev_mesh_device_found {
struct mgmt_ev_mesh_pkt_cmplt {
__u8 handle;
} __packed;
+
+#define MGMT_EV_CONN_SUBRATE 0x0033
+struct mgmt_ev_conn_subrate {
+ struct mgmt_addr_info addr;
+ __u8 status;
+ __le16 interval;
+ __le16 subrate;
+ __le16 latency;
+ __le16 cont_num;
+ __le16 supv_timeout;
+} __packed;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a2da7876b6b4..df3be484afb4 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -5867,6 +5867,17 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
}
}
+ /* If we are central and have subrate parameters stored, queue a
+ * connection rate request to apply them.
+ */
+ if (conn->role == HCI_ROLE_MASTER && le_sci_capable(hdev)) {
+ struct hci_conn_params *p;
+
+ p = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
+ if (p && p->subrate_max)
+ hci_le_conn_rate_request(hdev, p);
+ }
+
unlock:
hci_update_passive_scan(hdev);
hci_dev_unlock(hdev);
@@ -7371,16 +7382,23 @@ static void hci_le_conn_rate_change_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
- if (ev->status)
- return;
-
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
- conn->le_conn_interval = le16_to_cpu(ev->interval);
- conn->le_conn_latency = le16_to_cpu(ev->latency);
- conn->le_supv_timeout = le16_to_cpu(ev->supv_timeout);
+ /* Only update the stored rate parameters on success; on
+ * failure the values in the event are not valid. Userspace is
+ * notified either way.
+ */
+ if (!ev->status) {
+ conn->le_rate_interval = le16_to_cpu(ev->interval);
+ conn->le_subrate = le16_to_cpu(ev->subrate);
+ conn->le_rate_latency = le16_to_cpu(ev->latency);
+ conn->le_cont_num = le16_to_cpu(ev->cont_number);
+ conn->le_rate_supv_timeout =
+ le16_to_cpu(ev->supv_timeout);
+ }
+ mgmt_conn_subrate_notify(hdev, conn, ev->status);
}
hci_dev_unlock(hdev);
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index cd3e39c8bb86..30c7949ce203 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -7271,6 +7271,46 @@ int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
+int hci_le_conn_rate_sync(struct hci_dev *hdev, struct hci_conn *conn,
+ struct hci_conn_params *params)
+{
+ struct hci_cp_le_conn_rate cp;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.handle = cpu_to_le16(conn->handle);
+ cp.interval_min = cpu_to_le16(params->rate_min_interval);
+ cp.interval_max = cpu_to_le16(params->rate_max_interval);
+ cp.subrate_min = cpu_to_le16(params->subrate_min);
+ cp.subrate_max = cpu_to_le16(params->subrate_max);
+ cp.max_latency = cpu_to_le16(params->max_latency);
+ cp.cont_num = cpu_to_le16(params->cont_num);
+ cp.supv_timeout = cpu_to_le16(params->rate_supv_timeout);
+ cp.min_ce_len = cpu_to_le16(0x0000);
+ cp.max_ce_len = cpu_to_le16(0x0000);
+
+ return __hci_cmd_sync_status(hdev, HCI_OP_LE_CONN_RATE,
+ sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_le_conn_rate_request_sync(struct hci_dev *hdev, void *data)
+{
+ struct hci_conn_params *params = data;
+ struct hci_conn *conn;
+
+ conn = hci_conn_hash_lookup_le(hdev, ¶ms->addr, params->addr_type);
+ if (!conn)
+ return -ECANCELED;
+
+ return hci_le_conn_rate_sync(hdev, conn, params);
+}
+
+int hci_le_conn_rate_request(struct hci_dev *hdev,
+ struct hci_conn_params *params)
+{
+ return hci_cmd_sync_queue(hdev, hci_le_conn_rate_request_sync,
+ params, NULL);
+}
+
static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
{
struct hci_conn *conn = data;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 58f01fbfcf71..39b430b864cc 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -8160,6 +8160,105 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
NULL, 0);
}
+static int load_conn_subrate(struct sock *sk, struct hci_dev *hdev, void *data,
+ u16 len)
+{
+ struct mgmt_cp_load_conn_subrate *cp = data;
+ const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
+ sizeof(struct mgmt_conn_subrate));
+ u16 param_count, expected_len;
+ int i;
+
+ if (!lmp_le_capable(hdev) || !le_sci_capable(hdev))
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_SUBRATE,
+ MGMT_STATUS_NOT_SUPPORTED);
+
+ param_count = __le16_to_cpu(cp->param_count);
+ if (param_count > max_param_count) {
+ bt_dev_err(hdev, "load_conn_subrate: too big param_count value %u",
+ param_count);
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_SUBRATE,
+ MGMT_STATUS_INVALID_PARAMS);
+ }
+
+ expected_len = struct_size(cp, params, param_count);
+ if (expected_len != len) {
+ bt_dev_err(hdev, "load_conn_subrate: expected %u bytes, got %u bytes",
+ expected_len, len);
+ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_SUBRATE,
+ MGMT_STATUS_INVALID_PARAMS);
+ }
+
+ bt_dev_dbg(hdev, "param_count %u", param_count);
+
+ hci_dev_lock(hdev);
+
+ for (i = 0; i < param_count; i++) {
+ struct mgmt_conn_subrate *param = &cp->params[i];
+ struct hci_conn_params *hci_param;
+ u16 min, max, subrate_min, subrate_max;
+ u16 max_latency, cont_num, supv_timeout;
+ u8 addr_type;
+
+ bt_dev_dbg(hdev, "Adding subrate %pMR (type %u)",
+ ¶m->addr.bdaddr, param->addr.type);
+
+ if (param->addr.type == BDADDR_LE_PUBLIC) {
+ addr_type = ADDR_LE_DEV_PUBLIC;
+ } else if (param->addr.type == BDADDR_LE_RANDOM) {
+ addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ bt_dev_err(hdev, "ignoring invalid connection subrate parameters");
+ continue;
+ }
+
+ min = le16_to_cpu(param->min_interval);
+ max = le16_to_cpu(param->max_interval);
+ subrate_min = le16_to_cpu(param->subrate_min);
+ subrate_max = le16_to_cpu(param->subrate_max);
+ max_latency = le16_to_cpu(param->max_latency);
+ cont_num = le16_to_cpu(param->cont_num);
+ supv_timeout = le16_to_cpu(param->supv_timeout);
+
+ hci_param = hci_conn_params_add(hdev, ¶m->addr.bdaddr,
+ addr_type);
+ if (!hci_param) {
+ bt_dev_err(hdev, "failed to add connection parameters");
+ continue;
+ }
+
+ hci_param->rate_min_interval = min;
+ hci_param->rate_max_interval = max;
+ hci_param->subrate_min = subrate_min;
+ hci_param->subrate_max = subrate_max;
+ hci_param->max_latency = max_latency;
+ hci_param->cont_num = cont_num;
+ hci_param->rate_supv_timeout = supv_timeout;
+
+ /* If the device is connected as central check if the
+ * connection rate parameters need to be updated.
+ */
+ if (!i && param_count == 1) {
+ struct hci_conn *conn;
+
+ conn = hci_conn_hash_lookup_le(hdev,
+ &hci_param->addr,
+ addr_type);
+ if (conn && conn->role == HCI_ROLE_MASTER &&
+ (conn->le_rate_interval < min ||
+ conn->le_rate_interval > max ||
+ conn->le_subrate < subrate_min ||
+ conn->le_subrate > subrate_max))
+ hci_le_conn_rate_request(hdev, hci_param);
+ }
+ }
+
+ hci_dev_unlock(hdev);
+
+ return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_SUBRATE, 0,
+ NULL, 0);
+}
+
static int set_external_config(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
@@ -9577,6 +9676,8 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
HCI_MGMT_VAR_LEN },
{ mesh_send_cancel, MGMT_MESH_SEND_CANCEL_SIZE },
{ mgmt_hci_cmd_sync, MGMT_HCI_CMD_SYNC_SIZE, HCI_MGMT_VAR_LEN },
+ { load_conn_subrate, MGMT_LOAD_CONN_SUBRATE_SIZE,
+ HCI_MGMT_VAR_LEN },
};
void mgmt_index_added(struct hci_dev *hdev)
@@ -10725,6 +10826,23 @@ int mgmt_init(void)
return hci_mgmt_chan_register(&chan);
}
+void mgmt_conn_subrate_notify(struct hci_dev *hdev, struct hci_conn *conn,
+ u8 status)
+{
+ struct mgmt_ev_conn_subrate ev;
+
+ bacpy(&ev.addr.bdaddr, &conn->dst);
+ ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
+ ev.status = mgmt_status(status);
+ ev.interval = cpu_to_le16(conn->le_rate_interval);
+ ev.subrate = cpu_to_le16(conn->le_subrate);
+ ev.latency = cpu_to_le16(conn->le_rate_latency);
+ ev.cont_num = cpu_to_le16(conn->le_cont_num);
+ ev.supv_timeout = cpu_to_le16(conn->le_rate_supv_timeout);
+
+ mgmt_event(MGMT_EV_CONN_SUBRATE, hdev, &ev, sizeof(ev), NULL);
+}
+
void mgmt_exit(void)
{
hci_mgmt_chan_unregister(&chan);
--
2.54.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* RE: [v1,1/3] Bluetooth: Add support for Shorter Connection Interval (SCI) feature
2026-07-24 16:35 [PATCH v1 1/3] Bluetooth: Add support for Shorter Connection Interval (SCI) feature Luiz Augusto von Dentz
2026-07-24 16:35 ` [PATCH v1 2/3] Bluetooth: Add MGMT Shorter Connection Interval setting Luiz Augusto von Dentz
2026-07-24 16:35 ` [PATCH v1 3/3] Bluetooth: Add MGMT Load Connection Subrate command Luiz Augusto von Dentz
@ 2026-07-24 17:59 ` bluez.test.bot
2 siblings, 0 replies; 4+ messages in thread
From: bluez.test.bot @ 2026-07-24 17:59 UTC (permalink / raw)
To: linux-bluetooth, luiz.dentz
[-- Attachment #1: Type: text/plain, Size: 3436 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1134097
---Test result---
Test Summary:
CheckPatch FAIL 4.45 seconds
VerifyFixes PASS 0.15 seconds
VerifySignedoff PASS 0.14 seconds
GitLint PASS 1.04 seconds
SubjectPrefix PASS 0.42 seconds
BuildKernel PASS 27.19 seconds
CheckAllWarning PASS 29.86 seconds
CheckSparse PASS 29.21 seconds
BuildKernel32 PASS 26.32 seconds
CheckKernelLLVM SKIP 0.00 seconds
TestRunnerSetup PASS 505.63 seconds
TestRunner_l2cap-tester PASS 62.58 seconds
TestRunner_iso-tester PASS 88.30 seconds
TestRunner_bnep-tester PASS 19.73 seconds
TestRunner_mgmt-tester FAIL 227.58 seconds
TestRunner_rfcomm-tester PASS 26.33 seconds
TestRunner_sco-tester PASS 32.97 seconds
TestRunner_ioctl-tester PASS 27.62 seconds
TestRunner_mesh-tester FAIL 27.10 seconds
TestRunner_smp-tester PASS 31.48 seconds
TestRunner_userchan-tester PASS 21.04 seconds
TestRunner_6lowpan-tester PASS 23.86 seconds
IncrementalBuild PASS 62.57 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v1,3/3] Bluetooth: Add MGMT Load Connection Subrate command
WARNING: Prefer using '"%s...", __func__' to using 'load_conn_subrate', this function's name, in a string
#350: FILE: net/bluetooth/mgmt.c:8178:
+ bt_dev_err(hdev, "load_conn_subrate: too big param_count value %u",
WARNING: Prefer using '"%s...", __func__' to using 'load_conn_subrate', this function's name, in a string
#358: FILE: net/bluetooth/mgmt.c:8186:
+ bt_dev_err(hdev, "load_conn_subrate: expected %u bytes, got %u bytes",
total: 0 errors, 2 warnings, 0 checks, 308 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/patch/14709292.patch has style problems, please review.
NOTE: Ignored message types: UNKNOWN_COMMIT_ID
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4
Failed Test Cases
Read Exp Feature - Success Failed 0.254 seconds
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0
Failed Test Cases
Mesh - Send cancel - 1 Timed out 2.537 seconds
Mesh - Send cancel - 2 Timed out 1.990 seconds
https://github.com/bluez/bluetooth-next/pull/488
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-07-24 17:59 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-24 16:35 [PATCH v1 1/3] Bluetooth: Add support for Shorter Connection Interval (SCI) feature Luiz Augusto von Dentz
2026-07-24 16:35 ` [PATCH v1 2/3] Bluetooth: Add MGMT Shorter Connection Interval setting Luiz Augusto von Dentz
2026-07-24 16:35 ` [PATCH v1 3/3] Bluetooth: Add MGMT Load Connection Subrate command Luiz Augusto von Dentz
2026-07-24 17:59 ` [v1,1/3] Bluetooth: Add support for Shorter Connection Interval (SCI) feature bluez.test.bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.