[PATCH BlueZ v1 08/12] client/mgmt: Add conn-subrate command

Luiz Augusto von Dentz <[email protected]> Fri, 24 Jul 2026 15:12:21 -0400
Newsgroups org.kernel.vger.linux-bluetooth
Message-ID <[email protected]>
From: Luiz Augusto von Dentz <[email protected]>

Add conn-subrate command to load connection subrate parameters
for a device via MGMT_OP_LOAD_CONN_SUBRATE.

Usage:
  conn-subrate [-t type] <address> <min_interval> <max_interval> \
               <subrate_min> <subrate_max> <max_latency> \
               <cont_num> <supv_timeout>
---
 client/mgmt.c             | 88 +++++++++++++++++++++++++++++++++++++++
 doc/bluetoothctl-mgmt.rst | 21 ++++++++++
 2 files changed, 109 insertions(+)

diff --git a/client/mgmt.c b/client/mgmt.c
index 50558a313866..cd2ef80221ad 100644
--- a/client/mgmt.c
+++ b/client/mgmt.c
@@ -6038,6 +6038,90 @@ static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index)
 								NULL, NULL);
 }
 
+static void conn_subrate_rsp(uint8_t status, uint16_t len, const void *param,
+							void *user_data)
+{
+	if (status != 0)
+		error("Load Connection Subrate failed with status 0x%02x (%s)",
+						status, mgmt_errstr(status));
+	else
+		print("Connection Subrate loaded successfully");
+
+	bt_shell_noninteractive_quit(EXIT_SUCCESS);
+}
+
+static const struct option conn_subrate_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ "type",	1, 0, 't' },
+	{ 0, 0, 0, 0 }
+};
+
+static void cmd_conn_subrate(int argc, char **argv)
+{
+	struct mgmt_cp_load_conn_subrate *cp;
+	uint8_t type = BDADDR_LE_PUBLIC;
+	int opt;
+	uint16_t index;
+	size_t cp_size;
+
+	while ((opt = getopt_long(argc, argv, "+t:h", conn_subrate_options,
+								NULL)) != -1) {
+		switch (opt) {
+		case 't':
+			type = strtol(optarg, NULL, 0);
+			break;
+		case 'h':
+			bt_shell_usage();
+			optind = 0;
+			return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+		default:
+			bt_shell_usage();
+			optind = 0;
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 0;
+
+	if (argc < 8) {
+		bt_shell_usage();
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+
+	index = mgmt_index;
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	cp_size = sizeof(*cp) + sizeof(struct mgmt_conn_subrate);
+	cp = malloc0(cp_size);
+	if (!cp) {
+		error("Unable to allocate memory");
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+
+	cp->param_count = cpu_to_le16(1);
+	str2ba(argv[0], &cp->params[0].addr.bdaddr);
+	cp->params[0].addr.type = type;
+	cp->params[0].min_interval = cpu_to_le16(strtol(argv[1], NULL, 0));
+	cp->params[0].max_interval = cpu_to_le16(strtol(argv[2], NULL, 0));
+	cp->params[0].subrate_min = cpu_to_le16(strtol(argv[3], NULL, 0));
+	cp->params[0].subrate_max = cpu_to_le16(strtol(argv[4], NULL, 0));
+	cp->params[0].max_latency = cpu_to_le16(strtol(argv[5], NULL, 0));
+	cp->params[0].cont_num = cpu_to_le16(strtol(argv[6], NULL, 0));
+	cp->params[0].supv_timeout = cpu_to_le16(strtol(argv[7], NULL, 0));
+
+	if (mgmt_send(mgmt, MGMT_OP_LOAD_CONN_SUBRATE, index, cp_size, cp,
+					conn_subrate_rsp, NULL, NULL) == 0) {
+		error("Unable to send load connection subrate command");
+		free(cp);
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+
+	free(cp);
+}
+
 static void cmd_select(int argc, char **argv)
 {
 	mgmt_cancel_all(mgmt);
@@ -6233,6 +6317,10 @@ static const struct bt_shell_menu mgmt_menu = {
 		cmd_get_flags,		"Get device flags"		},
 	{ "set-flags",		"[-f flags] [-t type] <address>",
 		cmd_set_flags,		"Set device flags"		},
+	{ "conn-subrate",	"[-t type] <address> <min_interval> "
+				"<max_interval> <subrate_min> <subrate_max> "
+				"<max_latency> <cont_num> <supv_timeout>",
+		cmd_conn_subrate,	"Load Connection Subrate"	},
 	{ "hci-cmd",		"<opcode> [event] [timeout] [param...]",
 		cmd_hci_cmd,	"Send HCI Command and wait for Event"	},
 	{} },
diff --git a/doc/bluetoothctl-mgmt.rst b/doc/bluetoothctl-mgmt.rst
index 646c2dcb4365..91406041c3cb 100644
--- a/doc/bluetoothctl-mgmt.rst
+++ b/doc/bluetoothctl-mgmt.rst
@@ -1293,6 +1293,27 @@ Set device flags
 :Example Clear all flags for LE public device:
 	| **> set-flags -f 0x00 -t le_public 11:22:33:44:55:66**
 
+conn-subrate
+------------
+
+Load Connection Subrate
+
+:Usage: **> conn-subrate [-t type] <address> <min_interval> <max_interval>
+	<subrate_min> <subrate_max> <max_latency> <cont_num> <supv_timeout>**
+:[-t type]: Address type - 1 for LE Public, 2 for LE Random
+:<address>: Bluetooth address of the device
+:<min_interval>: Minimum connection interval (units of 0.125 ms)
+:<max_interval>: Maximum connection interval (units of 0.125 ms)
+:<subrate_min>: Minimum subrate factor
+:<subrate_max>: Maximum subrate factor
+:<max_latency>: Maximum peripheral latency (subrated connection events)
+:<cont_num>: Continuation number
+:<supv_timeout>: Supervision timeout (units of 10 ms)
+:Example Load subrate for LE public address device:
+	| **> conn-subrate -t 1 00:11:22:33:44:55 8 3200 1 4 0 2 200**
+:Example Load subrate for LE random address device:
+	| **> conn-subrate -t 2 AA:BB:CC:DD:EE:FF 16 1600 2 8 0 4 100**
+
 RESOURCES
 =========
 
-- 
2.54.0