Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ v1 1/2] client/mgmt: Add options to ltks command for loading entries
@ 2026-06-03 19:03 Luiz Augusto von Dentz
  2026-06-03 19:03 ` [PATCH BlueZ v1 2/2] doc/bluetoothctl-mgmt: Update ltks command documentation Luiz Augusto von Dentz
  2026-06-03 20:36 ` [BlueZ,v1,1/2] client/mgmt: Add options to ltks command for loading entries bluez.test.bot
  0 siblings, 2 replies; 3+ messages in thread
From: Luiz Augusto von Dentz @ 2026-06-03 19:03 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Add support for optionally specifying a single LTK entry when using
the ltks command. When called without arguments it clears all LTKs
(existing behavior). When called with an address and key parameters
it loads exactly one LTK entry, useful for testing.

Options:
  -a addr_type  Address type (1=LE Public, 2=LE Random)
  -t key_type   Key type (0=Unauthenticated, 1=Authenticated)
  -c central    Central flag (0 or 1)
  -e enc_size   Encryption key size (7-16)
  -d ediv       Encrypted Diversifier
  -r rand       Random number (64-bit)
  -k key        128-bit key as 32 hex characters
---
 client/mgmt.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 6 deletions(-)

diff --git a/client/mgmt.c b/client/mgmt.c
index 50558a313866..6d6ada95f43d 100644
--- a/client/mgmt.c
+++ b/client/mgmt.c
@@ -3535,21 +3535,107 @@ static void ltks_rsp(uint8_t status, uint16_t len, const void *param,
 	bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
+static const struct option ltks_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ "address-type", 1, 0, 'a' },
+	{ "type",	1, 0, 't' },
+	{ "central",	1, 0, 'c' },
+	{ "enc-size",	1, 0, 'e' },
+	{ "ediv",	1, 0, 'd' },
+	{ "rand",	1, 0, 'r' },
+	{ "key",	1, 0, 'k' },
+	{ 0, 0, 0, 0 }
+};
+
 static void cmd_ltks(int argc, char **argv)
 {
-	struct mgmt_cp_load_long_term_keys cp;
+	struct mgmt_cp_load_long_term_keys *cp;
+	uint8_t buf[sizeof(*cp) + sizeof(struct mgmt_ltk_info)];
+	uint16_t count = 0;
+	struct mgmt_ltk_info *ltk;
+	uint8_t addr_type = BDADDR_LE_PUBLIC;
+	int opt;
 	uint16_t index;
 
 	index = mgmt_index;
 	if (index == MGMT_INDEX_NONE)
 		index = 0;
 
-	memset(&cp, 0, sizeof(cp));
+	cp = (void *) buf;
+	memset(buf, 0, sizeof(buf));
+	ltk = &cp->keys[0];
 
-	if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index, sizeof(cp), &cp,
-						ltks_rsp, NULL, NULL) == 0) {
+	while ((opt = getopt_long(argc, argv, "+a:t:c:e:d:r:k:h",
+					ltks_options, NULL)) != -1) {
+		switch (opt) {
+		case 'a':
+			addr_type = strtol(optarg, NULL, 0);
+			if (addr_type != BDADDR_LE_PUBLIC &&
+					addr_type != BDADDR_LE_RANDOM) {
+				error("Invalid address type (expected 1=LE "
+							"Public, 2=LE Random)");
+				optind = 0;
+				return bt_shell_noninteractive_quit(
+								EXIT_FAILURE);
+			}
+			break;
+		case 't':
+			ltk->type = strtol(optarg, NULL, 0);
+			break;
+		case 'c':
+			ltk->central = strtol(optarg, NULL, 0);
+			break;
+		case 'e':
+			ltk->enc_size = strtol(optarg, NULL, 0);
+			break;
+		case 'd':
+			ltk->ediv = strtol(optarg, NULL, 0);
+			break;
+		case 'r':
+			ltk->rand = strtoull(optarg, NULL, 0);
+			break;
+		case 'k':
+			if (strlen(optarg) != 32) {
+				error("Invalid key length (expected 32 hex "
+								"chars)");
+				optind = 0;
+				return bt_shell_noninteractive_quit(
+								EXIT_FAILURE);
+			}
+			for (int i = 0; i < 16; i++) {
+				char byte[3] = { optarg[i * 2],
+						optarg[i * 2 + 1], 0 };
+				ltk->val[i] = strtol(byte, NULL, 16);
+			}
+			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 > 0) {
+		str2ba(argv[0], &ltk->addr.bdaddr);
+		ltk->addr.type = addr_type;
+		count = 1;
+	}
+
+	cp->key_count = cpu_to_le16(count);
+
+	if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index,
+				sizeof(*cp) + count * sizeof(*ltk), cp,
+				ltks_rsp, NULL, NULL) == 0) {
 		error("Unable to send load_ltks cmd");
-		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 }
 
@@ -6136,7 +6222,9 @@ static const struct bt_shell_menu mgmt_menu = {
 		cmd_unpair,		"Unpair device"			},
 	{ "keys",		NULL,
 		cmd_keys,		"Load Link Keys"		},
-	{ "ltks",		NULL,
+	{ "ltks",		"[-a addr_type] [-t key_type] [-c central] "
+				"[-e enc_size] [-d ediv] [-r rand] [-k key] "
+				"[address]",
 		cmd_ltks,		"Load Long Term Keys"		},
 	{ "irks",		"[--local index] [--file file path]",
 		cmd_irks,		"Load Identity Resolving Keys"	},
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-06-03 20:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-03 19:03 [PATCH BlueZ v1 1/2] client/mgmt: Add options to ltks command for loading entries Luiz Augusto von Dentz
2026-06-03 19:03 ` [PATCH BlueZ v1 2/2] doc/bluetoothctl-mgmt: Update ltks command documentation Luiz Augusto von Dentz
2026-06-03 20:36 ` [BlueZ,v1,1/2] client/mgmt: Add options to ltks command for loading entries bluez.test.bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox