client/mgmt: Add hci-cmd command

This adds hci-cmd command which uses the MGMT_OP_HCI_CMD_SYNC:

bluetoothctl> mgmt.hci-send 0xffff
bluetoothctl[44]: @ MGMT Com..nd (0x005b) plen 6  {0x0002}
        Opcode: 0xffff
        Event: 0x00
        Timeout: 0 seconds
        Parameters Length: 0
        Parameters[0]:
< HCI Command: Vendor (0x3f|0x03ff) plen 0
> HCI Event: Command Status (0x0f) plen 4
      Vendor (0x3f|0x03ff) ncmd 1
        Status: Unknown HCI Command (0x01)
@ MGMT Event: Command Status (0x0002) plen 3    {0x0002}
      Send HCI command and wait for event (0x005b)
        Status: Failed (0x03)
This commit is contained in:
Luiz Augusto von Dentz 2024-10-23 16:47:05 -04:00
parent 0580dc4bb6
commit 95e89cd2e4

View File

@ -2338,6 +2338,115 @@ static void cmd_set_flags(int argc, char **argv)
}
static uint8_t *str2bytearray(char *arg, uint8_t *val, long *val_len)
{
char *entry;
unsigned int i;
for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) {
long v;
char *endptr = NULL;
if (*entry == '\0')
continue;
if (i >= *val_len) {
bt_shell_printf("Too much data\n");
return NULL;
}
v = strtol(entry, &endptr, 0);
if (!endptr || *endptr != '\0' || v > UINT8_MAX) {
bt_shell_printf("Invalid value at index %d\n", i);
return NULL;
}
val[i] = v;
}
*val_len = i;
return val;
}
static void hci_cmd_rsp(uint8_t status, uint16_t len, const void *param,
void *user_data)
{
if (status != 0) {
error("HCI command failed with status 0x%02x (%s)",
status, mgmt_errstr(status));
bt_shell_noninteractive_quit(EXIT_FAILURE);
}
if (len > 0) {
bt_shell_printf("Response: ");
bt_shell_hexdump(param, len);
}
bt_shell_noninteractive_quit(EXIT_SUCCESS);
}
static void cmd_hci_cmd(int argc, char **argv)
{
struct {
struct mgmt_cp_hci_cmd_sync cp;
uint8_t data[UINT8_MAX];
} pkt;
char *endptr = NULL;
long value;
uint16_t index;
value = strtoul(argv[1], &endptr, 0);
if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
bt_shell_printf("Invalid opcode: %s", argv[1]);
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
memset(&pkt, 0, sizeof(pkt));
pkt.cp.opcode = cpu_to_le16(value);
if (argc > 2) {
endptr = NULL;
value = strtoul(argv[2], &endptr, 0);
if (!endptr || *endptr != '\0' || value > UINT8_MAX) {
bt_shell_printf("Invalid event: %s", argv[2]);
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
pkt.cp.event = value;
}
if (argc > 3) {
endptr = NULL;
value = strtoul(argv[3], &endptr, 0);
if (!endptr || *endptr != '\0' || value > UINT8_MAX) {
bt_shell_printf("Invalid timeout: %s", argv[2]);
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
pkt.cp.timeout = value;
}
if (argc > 4) {
value = sizeof(pkt.data);
if (!str2bytearray(argv[4], pkt.data, &value))
return bt_shell_noninteractive_quit(EXIT_FAILURE);
pkt.cp.params_len = value;
}
index = mgmt_index;
if (index == MGMT_INDEX_NONE)
index = 0;
if (mgmt_send(mgmt, MGMT_OP_HCI_CMD_SYNC, index,
sizeof(pkt.cp) + pkt.cp.params_len, &pkt,
hci_cmd_rsp, NULL, NULL) == 0) {
error("Unable to send HCI command");
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
}
/* Wrapper to get the index and opcode to the response callback */
struct command_data {
uint16_t id;
@ -6016,6 +6125,8 @@ 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" },
{ "hci-cmd", "<opcode> [event] [timeout] [param...]",
cmd_hci_cmd, "Send HCI Command and wait for Event" },
{} },
};