From patchwork Fri Jul 14 22:16:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Augusto von Dentz X-Patchwork-Id: 13314250 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 848BBC001DF for ; Fri, 14 Jul 2023 22:17:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229914AbjGNWRO (ORCPT ); Fri, 14 Jul 2023 18:17:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57416 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230044AbjGNWRN (ORCPT ); Fri, 14 Jul 2023 18:17:13 -0400 Received: from mail-pf1-x42b.google.com (mail-pf1-x42b.google.com [IPv6:2607:f8b0:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6B6D42D66 for ; Fri, 14 Jul 2023 15:16:59 -0700 (PDT) Received: by mail-pf1-x42b.google.com with SMTP id d2e1a72fcca58-666e3b15370so1852170b3a.0 for ; Fri, 14 Jul 2023 15:16:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1689373018; x=1691965018; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=vcsXkmGlI/kQ/GCGOi4dgRmgWpx9/0BdM/8L5iSsqPE=; b=afWC+en4sQKdBBNGR2PG4pgHDFxu28+E+xaNOKL1HyGN+3vTjoKOhiAs3qyueGBT1E vZRfBvp6ni/catxgDr/62QyW/WsSrMEp4Q6FAFr/LTpItV0PfC9INg0M/0vN5wcjCWx3 YrSPy61zNs1mkrHx3MMYBkeOXtQG90rYsWqtbGrkCYfB38fCw2F6W8sYNewZN6piBG2B lH/w99AcsX06GtwUYLIGlm1IBY9anK/BydVtkWxvF5URhu0FGPSHwZfqszbCbm9Hbwci eNS59b1uej1PZW70rmG1RDvbEAzGSdFlOJDy+DPB83d/+wm+9ISaPYyADEgndAbHzPkS cthw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689373018; x=1691965018; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=vcsXkmGlI/kQ/GCGOi4dgRmgWpx9/0BdM/8L5iSsqPE=; b=BJbYDkCjk36CVQHRB+E5k22qGu5fqoaf9SdXLb+E2+q3Ktfe4pSJiQ5ajxUUGJmc1U h8hoXMfRs6oEcMmpJCVXsDZYm9dAa+RCc1YcF1S1e+vgeeqy3C2PzF+AnhuUcOyi6FbN ouwdeFNql9ZtjjJdIrnZFnQyT46u8yoqxOEDr5g4faurnzv6BRryql9p8o3yZ4GADZAx uo8PdPxAiTBpR+gD1qUkjfAOAjkVPAEeu7Aqy4iH9Da1eYObLSuGrOHL2sM+MetpzjD4 qnhHJ3V/nTvOhNbaUU5f2OGzAyGWZHPTLEJC/c3bLPEM47KIXbrYtbeAHZJ1udbQP89X pyiQ== X-Gm-Message-State: ABy/qLY4LTzV4uZSS49+VUYMhx/BlQiF2piee+HI5sGn9UHBH+odGpU2 gJUAgP4LtNU+JSe9FzaHGrD6Q5jBdXU= X-Google-Smtp-Source: APBJJlENwGMV0hs+MTvlxiEoyMcCFAtstJWDngt3PY+Lvfuji1qpyMVoI7l2XI5Fkv+/sEXv69w5vQ== X-Received: by 2002:a05:6a00:1988:b0:67e:18c6:d2db with SMTP id d8-20020a056a00198800b0067e18c6d2dbmr4900071pfl.28.1689373016343; Fri, 14 Jul 2023 15:16:56 -0700 (PDT) Received: from lvondent-mobl4.. (c-71-236-201-58.hsd1.or.comcast.net. [71.236.201.58]) by smtp.gmail.com with ESMTPSA id e26-20020a62aa1a000000b0065438394fa4sm7790792pff.90.2023.07.14.15.16.54 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 14 Jul 2023 15:16:55 -0700 (PDT) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ] client: Add support for mgmt submenu Date: Fri, 14 Jul 2023 15:16:53 -0700 Message-Id: <20230714221653.2437444-1-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.40.1 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz This moves the functionality of btmgmt into client/mgmt.c so its commands become available on bluetoothctl via mgmt submenu. --- Makefile.tools | 11 +- client/main.c | 3 + tools/btmgmt.c => client/mgmt.c | 173 +- client/mgmt.h | 13 + tools/btmgmt.c | 6040 +------------------------------ 5 files changed, 89 insertions(+), 6151 deletions(-) copy tools/btmgmt.c => client/mgmt.c (98%) create mode 100644 client/mgmt.h diff --git a/Makefile.tools b/Makefile.tools index df4cad06589a..7d9697001b75 100644 --- a/Makefile.tools +++ b/Makefile.tools @@ -12,9 +12,11 @@ client_bluetoothctl_SOURCES = client/main.c \ client/adv_monitor.c \ client/gatt.h client/gatt.c \ client/admin.h client/admin.c \ - client/player.h client/player.c -client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \ - $(GLIB_LIBS) $(DBUS_LIBS) -lreadline + client/player.h client/player.c \ + client/mgmt.h client/mgmt.c +client_bluetoothctl_LDADD = lib/libbluetooth-internal.la \ + gdbus/libgdbus-internal.la src/libshared-glib.la \ + $(GLIB_LIBS) $(DBUS_LIBS) -lreadline endif if ZSH_COMPLETIONS @@ -505,7 +507,8 @@ tools_obexctl_SOURCES = tools/obexctl.c tools_obexctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \ $(GLIB_LIBS) $(DBUS_LIBS) -lreadline -tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c +tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c \ + client/mgmt.c tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la \ -lreadline if DEPRECATED diff --git a/client/main.c b/client/main.c index b433a22001a3..0eac5bdf5015 100644 --- a/client/main.c +++ b/client/main.c @@ -33,6 +33,7 @@ #include "adv_monitor.h" #include "admin.h" #include "player.h" +#include "mgmt.h" /* String display constants */ #define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF @@ -3190,6 +3191,7 @@ int main(int argc, char *argv[]) admin_add_submenu(); player_add_submenu(); + mgmt_add_submenu(); client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez"); @@ -3206,6 +3208,7 @@ int main(int argc, char *argv[]) admin_remove_submenu(); player_remove_submenu(); + mgmt_remove_submenu(); g_dbus_client_unref(client); diff --git a/tools/btmgmt.c b/client/mgmt.c similarity index 98% copy from tools/btmgmt.c copy to client/mgmt.c index 323c2671216e..c056d018a9da 100644 --- a/tools/btmgmt.c +++ b/client/mgmt.c @@ -33,6 +33,7 @@ #include "lib/hci_lib.h" #include "lib/sdp.h" #include "lib/sdp_lib.h" +#include "lib/uuid.h" #include "src/uuid-helper.h" #include "lib/mgmt.h" @@ -42,6 +43,7 @@ #include "src/shared/util.h" #include "src/shared/mgmt.h" #include "src/shared/shell.h" +#include "client/mgmt.h" #define SCAN_TYPE_BREDR (1 << BDADDR_BREDR) #define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM)) @@ -70,28 +72,6 @@ static int pending_index = 0; #define PROMPT_ON COLOR_BLUE "[mgmt]" COLOR_OFF "# " -static void set_index(const char *arg) -{ - if (!arg || !strcmp(arg, "none") || !strcmp(arg, "any") || - !strcmp(arg, "all")) - mgmt_index = MGMT_INDEX_NONE; - else if(strlen(arg) > 3 && !strncasecmp(arg, "hci", 3)) - mgmt_index = atoi(&arg[3]); - else - mgmt_index = atoi(arg); -} - -static bool parse_setting(int argc, char **argv, uint8_t *val) -{ - if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) - *val = 1; - else if (strcasecmp(argv[1], "off") == 0) - *val = 0; - else - *val = atoi(argv[1]); - return true; -} - static void update_prompt(uint16_t index) { char str[32]; @@ -106,6 +86,30 @@ static void update_prompt(uint16_t index) bt_shell_set_prompt(str); } +void mgmt_set_index(const char *arg) +{ + if (!arg || !strcmp(arg, "none") || !strcmp(arg, "any") || + !strcmp(arg, "all")) + mgmt_index = MGMT_INDEX_NONE; + else if (strlen(arg) > 3 && !strncasecmp(arg, "hci", 3)) + mgmt_index = atoi(&arg[3]); + else + mgmt_index = atoi(arg); + + update_prompt(mgmt_index); +} + +static bool parse_setting(int argc, char **argv, uint8_t *val) +{ + if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) + *val = 1; + else if (strcasecmp(argv[1], "off") == 0) + *val = 0; + else + *val = atoi(argv[1]); + return true; +} + #define print(fmt, arg...) do { \ bt_shell_printf(fmt "\n", ## arg); \ } while (0) @@ -2782,25 +2786,13 @@ static struct option find_service_options[] = { { 0, 0, 0, 0 } }; -static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid) -{ - if (uuid->type == SDP_UUID16) - sdp_uuid16_to_uuid128(uuid128, uuid); - else if (uuid->type == SDP_UUID32) - sdp_uuid32_to_uuid128(uuid128, uuid); - else - memcpy(uuid128, uuid, sizeof(*uuid)); -} - #define MAX_UUIDS 4 static void cmd_find_service(int argc, char **argv) { struct mgmt_cp_start_service_discovery *cp; uint8_t buf[sizeof(*cp) + 16 * MAX_UUIDS]; - uuid_t uuid; - uint128_t uint128; - uuid_t uuid128; + bt_uuid_t uuid; uint8_t type = SCAN_TYPE_DUAL; int8_t rssi; uint16_t count; @@ -2832,16 +2824,13 @@ static void cmd_find_service(int argc, char **argv) return bt_shell_noninteractive_quit(EXIT_FAILURE); } - if (bt_string2uuid(&uuid, optarg) < 0) { + if (bt_string_to_uuid(&uuid, optarg) < 0) { print("Invalid UUID: %s", optarg); optind = 0; return bt_shell_noninteractive_quit(EXIT_FAILURE); } cp = (void *) buf; - uuid_to_uuid128(&uuid128, &uuid); - ntoh128((uint128_t *) uuid128.value.uuid128.data, - &uint128); - htob128(&uint128, (uint128_t *) cp->uuids[count++]); + bt_uuid_to_le(&uuid, cp->uuids[count++]); break; case 'r': rssi = atoi(optarg); @@ -3588,8 +3577,7 @@ static void cmd_unblock(int argc, char **argv) static void cmd_add_uuid(int argc, char **argv) { struct mgmt_cp_add_uuid cp; - uint128_t uint128; - uuid_t uuid, uuid128; + bt_uuid_t uuid; uint16_t index; if (argc < 3) { @@ -3601,16 +3589,13 @@ static void cmd_add_uuid(int argc, char **argv) if (index == MGMT_INDEX_NONE) index = 0; - if (bt_string2uuid(&uuid, argv[1]) < 0) { + if (bt_string_to_uuid(&uuid, argv[1]) < 0) { print("Invalid UUID: %s", argv[1]); return bt_shell_noninteractive_quit(EXIT_FAILURE); } memset(&cp, 0, sizeof(cp)); - - uuid_to_uuid128(&uuid128, &uuid); - ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128); - htob128(&uint128, (uint128_t *) cp.uuid); + bt_uuid_to_le(&uuid, cp.uuid); cp.svc_hint = atoi(argv[2]); @@ -3624,8 +3609,7 @@ static void cmd_add_uuid(int argc, char **argv) static void cmd_remove_uuid(int argc, char **argv) { struct mgmt_cp_remove_uuid cp; - uint128_t uint128; - uuid_t uuid, uuid128; + bt_uuid_t uuid; uint16_t index; if (argc < 2) { @@ -3637,16 +3621,14 @@ static void cmd_remove_uuid(int argc, char **argv) if (index == MGMT_INDEX_NONE) index = 0; - if (bt_string2uuid(&uuid, argv[1]) < 0) { + if (bt_string_to_uuid(&uuid, argv[1]) < 0) { print("Invalid UUID: %s", argv[1]); return bt_shell_noninteractive_quit(EXIT_FAILURE); } memset(&cp, 0, sizeof(cp)); - uuid_to_uuid128(&uuid128, &uuid); - ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128); - htob128(&uint128, (uint128_t *) cp.uuid); + bt_uuid_to_le(&uuid, cp.uuid); if (send_cmd(mgmt, MGMT_OP_REMOVE_UUID, index, sizeof(cp), &cp, class_rsp) == 0) { @@ -4665,7 +4647,7 @@ static void cmd_add_adv(int argc, char **argv) uint8_t uuid_type = 0; uint16_t timeout = 0, duration = 0; uint8_t instance; - uuid_t uuid; + bt_uuid_t uuid; bool success = false; bool quit = true; uint32_t flags = 0; @@ -4675,7 +4657,7 @@ static void cmd_add_adv(int argc, char **argv) add_adv_options, NULL)) != -1) { switch (opt) { case 'u': - if (bt_string2uuid(&uuid, optarg) < 0) { + if (bt_string_to_uuid(&uuid, optarg) < 0) { print("Invalid UUID: %s", optarg); goto done; } @@ -4685,22 +4667,21 @@ static void cmd_add_adv(int argc, char **argv) goto done; } - if (uuid.type == SDP_UUID16) { + if (uuid.type == BT_UUID16) { if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) { print("Too many UUIDs"); goto done; } - put_le16(uuid.value.uuid16, uuids + uuid_bytes); + bt_uuid_to_le(&uuid, uuids + uuid_bytes); uuid_bytes += 2; - } else if (uuid.type == SDP_UUID128) { + } else if (uuid.type == BT_UUID128) { if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) { print("Too many UUIDs"); goto done; } - bswap_128(uuid.value.uuid128.data, - uuids + uuid_bytes); + bt_uuid_to_le(&uuid, uuids + uuid_bytes); uuid_bytes += 16; } else { printf("Unsupported UUID type"); @@ -5131,7 +5112,7 @@ static void cmd_add_ext_adv_data(int argc, char **argv) size_t uuid_bytes = 0; uint8_t uuid_type = 0; uint8_t instance; - uuid_t uuid; + bt_uuid_t uuid; bool success = false; bool quit = true; uint16_t index; @@ -5140,7 +5121,7 @@ static void cmd_add_ext_adv_data(int argc, char **argv) add_ext_adv_data_options, NULL)) != -1) { switch (opt) { case 'u': - if (bt_string2uuid(&uuid, optarg) < 0) { + if (bt_string_to_uuid(&uuid, optarg) < 0) { print("Invalid UUID: %s", optarg); goto done; } @@ -5150,22 +5131,21 @@ static void cmd_add_ext_adv_data(int argc, char **argv) goto done; } - if (uuid.type == SDP_UUID16) { + if (uuid.type == BT_UUID16) { if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) { print("Too many UUIDs"); goto done; } - put_le16(uuid.value.uuid16, uuids + uuid_bytes); + bt_uuid_to_le(&uuid, uuids + uuid_bytes); uuid_bytes += 2; - } else if (uuid.type == SDP_UUID128) { + } else if (uuid.type == BT_UUID128) { if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) { print("Too many UUIDs"); goto done; } - bswap_128(uuid.value.uuid128.data, - uuids + uuid_bytes); + bt_uuid_to_le(&uuid, uuids + uuid_bytes); uuid_bytes += 16; } else { printf("Unsupported UUID type"); @@ -5837,13 +5817,11 @@ static void cmd_select(int argc, char **argv) mgmt_cancel_all(mgmt); mgmt_unregister_all(mgmt); - set_index(argv[1]); + mgmt_set_index(argv[1]); register_mgmt_callbacks(mgmt, mgmt_index); print("Selected index %u", mgmt_index); - - update_prompt(mgmt_index); } static const struct bt_shell_menu monitor_menu = { @@ -5855,7 +5833,7 @@ static const struct bt_shell_menu monitor_menu = { "features" }, { "remove", "", cmd_advmon_remove, "Remove advertisement monitor " }, - { "add-pattern", "[-h] ", + { "add-pattern", "[-,h] ", cmd_advmon_add_pattern, "Add advertisement monitor pattern" }, { "add-pattern-rssi", "[options] ", cmd_advmon_add_pattern_rssi, @@ -5863,8 +5841,9 @@ static const struct bt_shell_menu monitor_menu = { { } }, }; -static const struct bt_shell_menu main_menu = { - .name = "main", +static const struct bt_shell_menu mgmt_menu = { + .name = "mgmt", + .desc = "Management Submenu", .entries = { { "select", "", cmd_select, "Select a different index" }, @@ -6034,58 +6013,28 @@ static void mgmt_debug(const char *str, void *user_data) print("%s%s", prefix, str); } -static const char *index_option; - -static struct option main_options[] = { - { "index", 1, 0, 'i' }, - { 0, 0, 0, 0 } -}; - -static const char **optargs[] = { - &index_option -}; - -static const char *help[] = { - "Specify adapter index\n" -}; - -static const struct bt_shell_opt opt = { - .options = main_options, - .optno = sizeof(main_options) / sizeof(struct option), - .optstr = "i:V", - .optarg = optargs, - .help = help, -}; - -int main(int argc, char *argv[]) +bool mgmt_add_submenu(void) { - int status; - - bt_shell_init(argc, argv, &opt); - bt_shell_set_menu(&main_menu); - bt_shell_add_submenu(&monitor_menu); - mgmt = mgmt_new_default(); if (!mgmt) { fprintf(stderr, "Unable to open mgmt_socket\n"); - return EXIT_FAILURE; + return false; } + bt_shell_add_submenu(&mgmt_menu); + bt_shell_add_submenu(&monitor_menu); + if (getenv("MGMT_DEBUG")) mgmt_set_debug(mgmt, mgmt_debug, "mgmt: ", NULL); - if (index_option) - set_index(index_option); - register_mgmt_callbacks(mgmt, mgmt_index); - bt_shell_attach(fileno(stdin)); - update_prompt(mgmt_index); - status = bt_shell_run(); + return true; +} +void mgmt_remove_submenu(void) +{ mgmt_cancel_all(mgmt); mgmt_unregister_all(mgmt); mgmt_unref(mgmt); - - return status; } diff --git a/client/mgmt.h b/client/mgmt.h new file mode 100644 index 000000000000..5a2026eab6a2 --- /dev/null +++ b/client/mgmt.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * + * + */ + +bool mgmt_add_submenu(void); +void mgmt_remove_submenu(void); +void mgmt_set_index(const char *arg); diff --git a/tools/btmgmt.c b/tools/btmgmt.c index 323c2671216e..9b7f851bd8c6 100644 --- a/tools/btmgmt.c +++ b/tools/btmgmt.c @@ -11,6028 +11,11 @@ #endif #define _GNU_SOURCE -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include -#include "lib/bluetooth.h" -#include "lib/hci.h" -#include "lib/hci_lib.h" -#include "lib/sdp.h" -#include "lib/sdp_lib.h" - -#include "src/uuid-helper.h" -#include "lib/mgmt.h" - -#include "src/shared/mainloop.h" -#include "src/shared/io.h" -#include "src/shared/util.h" -#include "src/shared/mgmt.h" #include "src/shared/shell.h" - -#define SCAN_TYPE_BREDR (1 << BDADDR_BREDR) -#define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM)) -#define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE) - -static struct mgmt *mgmt = NULL; -static uint16_t mgmt_index = MGMT_INDEX_NONE; - -static bool discovery = false; -static bool resolve_names = true; - -static struct { - uint16_t index; - uint16_t req; - struct mgmt_addr_info addr; -} prompt = { - .index = MGMT_INDEX_NONE, -}; - - -static int pending_index = 0; - -#ifndef MIN -#define MIN(x, y) ((x) < (y) ? (x) : (y)) -#endif - -#define PROMPT_ON COLOR_BLUE "[mgmt]" COLOR_OFF "# " - -static void set_index(const char *arg) -{ - if (!arg || !strcmp(arg, "none") || !strcmp(arg, "any") || - !strcmp(arg, "all")) - mgmt_index = MGMT_INDEX_NONE; - else if(strlen(arg) > 3 && !strncasecmp(arg, "hci", 3)) - mgmt_index = atoi(&arg[3]); - else - mgmt_index = atoi(arg); -} - -static bool parse_setting(int argc, char **argv, uint8_t *val) -{ - if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) - *val = 1; - else if (strcasecmp(argv[1], "off") == 0) - *val = 0; - else - *val = atoi(argv[1]); - return true; -} - -static void update_prompt(uint16_t index) -{ - char str[32]; - - if (index == MGMT_INDEX_NONE) - snprintf(str, sizeof(str), "%s# ", - COLOR_BLUE "[mgmt]" COLOR_OFF); - else - snprintf(str, sizeof(str), - COLOR_BLUE "[hci%u]" COLOR_OFF "# ", index); - - bt_shell_set_prompt(str); -} - -#define print(fmt, arg...) do { \ - bt_shell_printf(fmt "\n", ## arg); \ -} while (0) - -#define error(fmt, arg...) do { \ - bt_shell_printf(COLOR_RED fmt "\n" COLOR_OFF, ## arg); \ -} while (0) - -static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen) -{ - size_t i, len; - - len = MIN((strlen(hexstr) / 2), buflen); - memset(buf, 0, len); - - for (i = 0; i < len; i++) - sscanf(hexstr + (i * 2), "%02hhX", &buf[i]); - - return len; -} - -static size_t bin2hex(const uint8_t *buf, size_t buflen, char *str, - size_t strlen) -{ - size_t i; - - for (i = 0; i < buflen && i < (strlen / 2); i++) - sprintf(str + (i * 2), "%02x", buf[i]); - - return i; -} - -static void print_eir(const uint8_t *eir, uint16_t eir_len) -{ - uint16_t parsed = 0; - char str[33]; - - while (parsed < eir_len - 1) { - uint8_t field_len = eir[0]; - - if (field_len == 0) - break; - - parsed += field_len + 1; - - if (parsed > eir_len) - break; - - switch (eir[1]) { - case 0x01: - print("Flags: 0x%02x", eir[2]); - break; - case 0x0d: - print("Class of Device: 0x%02x%02x%02x", - eir[4], eir[3], eir[2]); - break; - case 0x0e: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("SSP Hash C-192: %s", str); - break; - case 0x0f: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("SSP Rand R-192: %s", str); - break; - case 0x1b: - ba2str((bdaddr_t *) (eir + 2), str); - print("LE Device Address: %s (%s)", str, - eir[8] ? "random" : "public"); - break; - case 0x1c: - print("LE Role: 0x%02x", eir[2]); - break; - case 0x1d: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("SSP Hash C-256: %s", str); - break; - case 0x1e: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("SSP Rand R-256: %s", str); - break; - case 0x22: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("LE SC Confirmation Value: %s", str); - break; - case 0x23: - bin2hex(eir + 2, 16, str, sizeof(str)); - print("LE SC Random Value: %s", str); - break; - default: - print("Type %u: %u byte%s", eir[1], field_len - 1, - (field_len - 1) == 1 ? "" : "s"); - break; - } - - eir += field_len + 1; - } -} - -static bool load_identity(const char *path, struct mgmt_irk_info *irk) -{ - char *addr, *key; - unsigned int type; - int n; - FILE *fp; - - fp = fopen(path, "r"); - if (!fp) { - error("Failed to open identity file: %s", strerror(errno)); - return false; - } - - n = fscanf(fp, "%m[0-9a-f:] (type %u) %m[0-9a-f]", &addr, &type, &key); - - fclose(fp); - - if (n != 3) - return false; - - str2ba(addr, &irk->addr.bdaddr); - hex2bin(key, irk->val, sizeof(irk->val)); - - free(addr); - free(key); - - switch (type) { - case 0: - irk->addr.type = BDADDR_LE_PUBLIC; - break; - case 1: - irk->addr.type = BDADDR_LE_RANDOM; - break; - default: - error("Invalid address type %u", type); - return false; - } - - return true; -} - -static void controller_error(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_controller_error *ev = param; - - if (len < sizeof(*ev)) { - error("Too short (%u bytes) controller error event", len); - return; - } - - print("hci%u error 0x%02x", index, ev->error_code); -} - -static void index_added(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - print("hci%u added", index); -} - -static void index_removed(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - print("hci%u removed", index); -} - -static void unconf_index_added(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - print("hci%u added (unconfigured)", index); -} - -static void unconf_index_removed(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - print("hci%u removed (unconfigured)", index); -} - -static void ext_index_added(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_ext_index_added *ev = param; - - print("hci%u added (type %u bus %u)", index, ev->type, ev->bus); -} - -static void ext_index_removed(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_ext_index_removed *ev = param; - - print("hci%u removed (type %u bus %u)", index, ev->type, ev->bus); -} - -static const char *options_str[] = { - "external", - "public-address", -}; - -static const char *options2str(uint32_t options) -{ - static char str[256]; - unsigned i; - int off; - - off = 0; - str[0] = '\0'; - - for (i = 0; i < NELEM(options_str); i++) { - if ((options & (1 << i)) != 0) - off += snprintf(str + off, sizeof(str) - off, "%s ", - options_str[i]); - } - - return str; -} - -static void new_config_options(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const uint32_t *ev = param; - - if (len < sizeof(*ev)) { - error("Too short new_config_options event (%u)", len); - return; - } - - print("hci%u new_config_options: %s", index, options2str(get_le32(ev))); -} - -static const char *settings_str[] = { - "powered", - "connectable", - "fast-connectable", - "discoverable", - "bondable", - "link-security", - "ssp", - "br/edr", - "hs", - "le", - "advertising", - "secure-conn", - "debug-keys", - "privacy", - "configuration", - "static-addr", - "phy-configuration", - "wide-band-speech", - "cis-central", - "cis-peripheral", -}; - -static const char *settings2str(uint32_t settings) -{ - static char str[256]; - unsigned i; - int off; - - off = 0; - str[0] = '\0'; - - for (i = 0; i < NELEM(settings_str); i++) { - if ((settings & (1 << i)) != 0) - off += snprintf(str + off, sizeof(str) - off, "%s ", - settings_str[i]); - } - - return str; -} - -static void new_settings(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const uint32_t *ev = param; - - if (len < sizeof(*ev)) { - error("Too short new_settings event (%u)", len); - return; - } - - print("hci%u new_settings: %s", index, settings2str(get_le32(ev))); -} - -static void discovering(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_discovering *ev = param; - - if (len < sizeof(*ev)) { - error("Too short (%u bytes) discovering event", len); - return; - } - - print("hci%u type %u discovering %s", index, ev->type, - ev->discovering ? "on" : "off"); - - if (ev->discovering == 0 && discovery) - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void new_link_key(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_new_link_key *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid new_link_key length (%u bytes)", len); - return; - } - - ba2str(&ev->key.addr.bdaddr, addr); - print("hci%u new_link_key %s type 0x%02x pin_len %d store_hint %u", - index, addr, ev->key.type, ev->key.pin_len, ev->store_hint); -} - -static const char *typestr(uint8_t type) -{ - static const char *str[] = { "BR/EDR", "LE Public", "LE Random" }; - - if (type <= BDADDR_LE_RANDOM) - return str[type]; - - return "(unknown)"; -} - -static void connected(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_device_connected *ev = param; - uint16_t eir_len; - char addr[18]; - - if (len < sizeof(*ev)) { - error("Invalid connected event length (%u bytes)", len); - return; - } - - eir_len = get_le16(&ev->eir_len); - if (len != sizeof(*ev) + eir_len) { - error("Invalid connected event length (%u != eir_len %u)", - len, eir_len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s type %s connected eir_len %u", index, addr, - typestr(ev->addr.type), eir_len); -} - -static void disconnected(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_device_disconnected *ev = param; - char addr[18]; - uint8_t reason; - - if (len < sizeof(struct mgmt_addr_info)) { - error("Invalid disconnected event length (%u bytes)", len); - return; - } - - if (len < sizeof(*ev)) - reason = MGMT_DEV_DISCONN_UNKNOWN; - else - reason = ev->reason; - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s type %s disconnected with reason %u", - index, addr, typestr(ev->addr.type), reason); -} - -static void conn_failed(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_connect_failed *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid connect_failed event length (%u bytes)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s type %s connect failed (status 0x%02x, %s)", - index, addr, typestr(ev->addr.type), ev->status, - mgmt_errstr(ev->status)); -} - -static void auth_failed(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_auth_failed *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid auth_failed event length (%u bytes)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s auth failed with status 0x%02x (%s)", - index, addr, ev->status, mgmt_errstr(ev->status)); -} - -static void class_of_dev_changed(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_class_of_dev_changed *ev = param; - - if (len != sizeof(*ev)) { - error("Invalid class_of_dev_changed length (%u bytes)", len); - return; - } - - print("hci%u class of device changed: 0x%02x%02x%02x", index, - ev->dev_class[2], ev->dev_class[1], ev->dev_class[0]); -} - -static void local_name_changed(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_local_name_changed *ev = param; - - if (len != sizeof(*ev)) { - error("Invalid local_name_changed length (%u bytes)", len); - return; - } - - print("hci%u name changed: %s", index, ev->name); -} - -static void confirm_name_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_rp_confirm_name *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("confirm_name failed with status 0x%02x (%s)", status, - mgmt_errstr(status)); - return; - } - - if (len != sizeof(*rp)) { - error("confirm_name rsp length %u instead of %zu", - len, sizeof(*rp)); - return; - } - - ba2str(&rp->addr.bdaddr, addr); - - if (status != 0) - error("confirm_name for %s failed: 0x%02x (%s)", - addr, status, mgmt_errstr(status)); - else - print("confirm_name succeeded for %s", addr); -} - -static char *eir_get_name(const uint8_t *eir, uint16_t eir_len) -{ - uint8_t parsed = 0; - - if (eir_len < 2) - return NULL; - - while (parsed < eir_len - 1) { - uint8_t field_len = eir[0]; - - if (field_len == 0) - break; - - parsed += field_len + 1; - - if (parsed > eir_len) - break; - - /* Check for short of complete name */ - if (eir[1] == 0x09 || eir[1] == 0x08) - return strndup((char *) &eir[2], field_len - 1); - - eir += field_len + 1; - } - - return NULL; -} - -static unsigned int eir_get_flags(const uint8_t *eir, uint16_t eir_len) -{ - uint8_t parsed = 0; - - if (eir_len < 2) - return 0; - - while (parsed < eir_len - 1) { - uint8_t field_len = eir[0]; - - if (field_len == 0) - break; - - parsed += field_len + 1; - - if (parsed > eir_len) - break; - - /* Check for flags */ - if (eir[1] == 0x01) - return eir[2]; - - eir += field_len + 1; - } - - return 0; -} - -static void device_found(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_device_found *ev = param; - struct mgmt *mgmt = user_data; - uint16_t eir_len; - uint32_t flags; - - if (len < sizeof(*ev)) { - error("Too short device_found length (%u bytes)", len); - return; - } - - flags = btohl(ev->flags); - - eir_len = get_le16(&ev->eir_len); - if (len != sizeof(*ev) + eir_len) { - error("dev_found: expected %zu bytes, got %u bytes", - sizeof(*ev) + eir_len, len); - return; - } - - if (discovery) { - char addr[18], *name; - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u dev_found: %s type %s rssi %d " - "flags 0x%04x ", index, addr, - typestr(ev->addr.type), ev->rssi, flags); - - if (ev->addr.type != BDADDR_BREDR) - print("AD flags 0x%02x ", - eir_get_flags(ev->eir, eir_len)); - - name = eir_get_name(ev->eir, eir_len); - if (name) - print("name %s", name); - else - print("eir_len %u", eir_len); - - free(name); - } - - if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) { - struct mgmt_cp_confirm_name cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, &ev->addr, sizeof(cp.addr)); - if (resolve_names) - cp.name_known = 0; - else - cp.name_known = 1; - - mgmt_reply(mgmt, MGMT_OP_CONFIRM_NAME, index, sizeof(cp), &cp, - confirm_name_rsp, NULL, NULL); - } -} - -static void pin_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("PIN Code reply failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("PIN Reply successful"); -} - -static int mgmt_pin_reply(uint16_t index, const struct mgmt_addr_info *addr, - const char *pin, size_t len) -{ - struct mgmt_cp_pin_code_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(cp.addr)); - cp.pin_len = len; - memcpy(cp.pin_code, pin, len); - - return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_REPLY, index, - sizeof(cp), &cp, pin_rsp, NULL, NULL); -} - -static void pin_neg_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("PIN Neg reply failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("PIN Negative Reply successful"); -} - -static int mgmt_pin_neg_reply(uint16_t index, const struct mgmt_addr_info *addr) -{ - struct mgmt_cp_pin_code_neg_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(cp.addr)); - - return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_NEG_REPLY, index, - sizeof(cp), &cp, pin_neg_rsp, NULL, NULL); -} - -static void confirm_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("User Confirm reply failed. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("User Confirm Reply successful"); -} - -static int mgmt_confirm_reply(uint16_t index, const struct mgmt_addr_info *addr) -{ - struct mgmt_cp_user_confirm_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(*addr)); - - return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_REPLY, index, - sizeof(cp), &cp, confirm_rsp, NULL, NULL); -} - -static void confirm_neg_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Confirm Neg reply failed. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("User Confirm Negative Reply successful"); -} - -static int mgmt_confirm_neg_reply(uint16_t index, - const struct mgmt_addr_info *addr) -{ - struct mgmt_cp_user_confirm_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(*addr)); - - return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_NEG_REPLY, index, - sizeof(cp), &cp, confirm_neg_rsp, NULL, NULL); -} - -static void passkey_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("User Passkey reply failed. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("User Passkey Reply successful"); -} - -static int mgmt_passkey_reply(uint16_t index, const struct mgmt_addr_info *addr, - uint32_t passkey) -{ - struct mgmt_cp_user_passkey_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(*addr)); - put_le32(passkey, &cp.passkey); - - return mgmt_reply(mgmt, MGMT_OP_USER_PASSKEY_REPLY, index, - sizeof(cp), &cp, passkey_rsp, NULL, NULL); -} - -static void passkey_neg_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Passkey Neg reply failed. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("User Passkey Negative Reply successful"); -} - -static int mgmt_passkey_neg_reply(uint16_t index, - const struct mgmt_addr_info *addr) -{ - struct mgmt_cp_user_passkey_reply cp; - - memset(&cp, 0, sizeof(cp)); - memcpy(&cp.addr, addr, sizeof(*addr)); - - return mgmt_reply(mgmt, MGMT_OP_USER_PASSKEY_NEG_REPLY, index, - sizeof(cp), &cp, passkey_neg_rsp, NULL, NULL); -} - -static void prompt_input(const char *input, void *user_data) -{ - size_t len; - - len = strlen(input); - - switch (prompt.req) { - case MGMT_EV_PIN_CODE_REQUEST: - if (len) - mgmt_pin_reply(prompt.index, &prompt.addr, input, len); - else - mgmt_pin_neg_reply(prompt.index, &prompt.addr); - break; - case MGMT_EV_USER_PASSKEY_REQUEST: - if (strlen(input) > 0) - mgmt_passkey_reply(prompt.index, &prompt.addr, - atoi(input)); - else - mgmt_passkey_neg_reply(prompt.index, - &prompt.addr); - break; - case MGMT_EV_USER_CONFIRM_REQUEST: - if (input[0] == 'y' || input[0] == 'Y') - mgmt_confirm_reply(prompt.index, &prompt.addr); - else - mgmt_confirm_neg_reply(prompt.index, &prompt.addr); - break; - } -} - -static void ask(uint16_t index, uint16_t req, const struct mgmt_addr_info *addr, - const char *fmt, ...) -{ - char msg[256]; - va_list ap; - int off; - - prompt.index = index; - prompt.req = req; - memcpy(&prompt.addr, addr, sizeof(*addr)); - - va_start(ap, fmt); - off = vsnprintf(msg, sizeof(msg), fmt, ap); - va_end(ap); - - snprintf(msg + off, sizeof(msg) - off, " %s ", - COLOR_BOLDGRAY ">>" COLOR_OFF); - - bt_shell_prompt_input("", msg, prompt_input, NULL); -} - -static void request_pin(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_pin_code_request *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid pin_code request length (%u bytes)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s request PIN", index, addr); - - ask(index, MGMT_EV_PIN_CODE_REQUEST, &ev->addr, - "PIN Request (press enter to reject)"); -} - -static void user_confirm(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_user_confirm_request *ev = param; - uint32_t val; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid user_confirm request length (%u)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - val = get_le32(&ev->value); - - print("hci%u %s User Confirm %06u hint %u", index, addr, - val, ev->confirm_hint); - - if (ev->confirm_hint) - ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr, - "Accept pairing with %s (yes/no)", addr); - else - ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr, - "Confirm value %06u for %s (yes/no)", val, addr); -} - -static void request_passkey(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_user_passkey_request *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid passkey request length (%u bytes)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s request passkey", index, addr); - - ask(index, MGMT_EV_USER_PASSKEY_REQUEST, &ev->addr, - "Passkey Request (press enter to reject)"); -} - -static void passkey_notify(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_passkey_notify *ev = param; - char addr[18]; - - if (len != sizeof(*ev)) { - error("Invalid passkey request length (%u bytes)", len); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u %s request passkey", index, addr); - - print("Passkey Notify: %06u (entered %u)", get_le32(&ev->passkey), - ev->entered); -} - -static void local_oob_data_updated(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_local_oob_data_updated *ev = param; - uint16_t eir_len; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) local_oob_updated event", len); - return; - } - - eir_len = le16_to_cpu(ev->eir_len); - if (len != sizeof(*ev) + eir_len) { - error("local_oob_updated: expected %zu bytes, got %u bytes", - sizeof(*ev) + eir_len, len); - return; - } - - print("hci%u oob data updated: type %u len %u", index, - ev->type, eir_len); -} - -static void advertising_added(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_advertising_added *ev = param; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) advertising_added event", len); - return; - } - - print("hci%u advertising_added: instance %u", index, ev->instance); -} - -static void advertising_removed(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_ev_advertising_removed *ev = param; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) advertising_removed event", len); - return; - } - - print("hci%u advertising_removed: instance %u", index, ev->instance); -} - -static void flags_changed(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_device_flags_changed *ev = param; - char addr[18]; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) %s event", len, __func__); - return; - } - - ba2str(&ev->addr.bdaddr, addr); - print("hci%u device_flags_changed: %s (%s)", index, addr, - typestr(ev->addr.type)); - print(" supp: 0x%08x curr: 0x%08x", - ev->supported_flags, ev->current_flags); -} - -static void advmon_added(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_adv_monitor_added *ev = param; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) %s event", len, __func__); - return; - } - - print("hci%u %s: handle %u", index, __func__, - le16_to_cpu(ev->monitor_handle)); -} - -static void advmon_removed(uint16_t index, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_ev_adv_monitor_removed *ev = param; - - if (len < sizeof(*ev)) { - error("Too small (%u bytes) %s event", len, __func__); - return; - } - - print("hci%u %s: handle %u", index, __func__, - le16_to_cpu(ev->monitor_handle)); -} - -static void version_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_version *rp = param; - - if (status != 0) { - error("Reading mgmt version failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small version reply (%u bytes)", len); - goto done; - } - - print("MGMT Version %u, revision %u", rp->version, - get_le16(&rp->revision)); - -done: - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_revision(int argc, char **argv) -{ - if (mgmt_send(mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, - 0, NULL, version_rsp, NULL, NULL) == 0) { - error("Unable to send read_version cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void commands_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_commands *rp = param; - uint16_t num_commands, num_events; - size_t expected_len; - int i; - - if (status != 0) { - error("Read Supported Commands failed: status 0x%02x (%s)", - status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small commands reply (%u bytes)", len); - goto done; - } - - num_commands = get_le16(&rp->num_commands); - num_events = get_le16(&rp->num_events); - - expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) + - num_events * sizeof(uint16_t); - - if (len < expected_len) { - error("Too small commands reply (%u != %zu)", - len, expected_len); - goto done; - } - - print("%u commands:", num_commands); - for (i = 0; i < num_commands; i++) { - uint16_t op = get_le16(rp->opcodes + i); - print("\t%s (0x%04x)", mgmt_opstr(op), op); - } - - print("%u events:", num_events); - for (i = 0; i < num_events; i++) { - uint16_t ev = get_le16(rp->opcodes + num_commands + i); - print("\t%s (0x%04x)", mgmt_evstr(ev), ev); - } - -done: - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_commands(int argc, - char **argv) -{ - if (mgmt_send(mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, - 0, NULL, commands_rsp, NULL, NULL) == 0) { - error("Unable to send read_commands cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void config_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_config_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint32_t supported_options, missing_options; - - if (status != 0) { - error("Reading hci%u config failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - print("hci%u:\tUnconfigured controller", index); - - print("\tmanufacturer %u", le16_to_cpu(rp->manufacturer)); - - supported_options = le32_to_cpu(rp->supported_options); - print("\tsupported options: %s", options2str(supported_options)); - - missing_options = le32_to_cpu(rp->missing_options); - print("\tmissing options: %s", options2str(missing_options)); - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_unconf_index_list *rp = param; - uint16_t count; - unsigned int i; - - if (status != 0) { - error("Reading index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small index list reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = le16_to_cpu(rp->num_controllers); - - if (len < sizeof(*rp) + count * sizeof(uint16_t)) { - error("Index count (%u) doesn't match reply length (%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Unconfigured index list with %u item%s", - count, count != 1 ? "s" : ""); - - for (i = 0; i < count; i++) { - uint16_t index = le16_to_cpu(rp->index[i]); - - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL, - config_info_rsp, UINT_TO_PTR(index), NULL)) { - error("Unable to send read_config_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - pending_index++; - } - - if (!count) - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_config(int argc, char **argv) -{ - if (mgmt_index == MGMT_INDEX_NONE) { - if (!mgmt_send(mgmt, MGMT_OP_READ_UNCONF_INDEX_LIST, - MGMT_INDEX_NONE, 0, NULL, - unconf_index_rsp, mgmt, NULL)) { - error("Unable to send unconf_index_list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - return; - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, mgmt_index, 0, NULL, - config_info_rsp, UINT_TO_PTR(index), NULL)) { - error("Unable to send read_config_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void config_options_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_config_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint32_t supported_options, missing_options; - - if (status != 0) { - error("Reading hci%u config failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - print("hci%u:\tConfiguration options", index); - - supported_options = le32_to_cpu(rp->supported_options); - print("\tsupported options: %s", options2str(supported_options)); - - missing_options = le32_to_cpu(rp->missing_options); - print("\tmissing options: %s", options2str(missing_options)); - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint32_t supported_settings, current_settings; - char addr[18]; - - if (status != 0) { - error("Reading hci%u info failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - print("hci%u:\tPrimary controller", index); - - ba2str(&rp->bdaddr, addr); - print("\taddr %s version %u manufacturer %u class 0x%02x%02x%02x", - addr, rp->version, le16_to_cpu(rp->manufacturer), - rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]); - - supported_settings = le32_to_cpu(rp->supported_settings); - print("\tsupported settings: %s", settings2str(supported_settings)); - - current_settings = le32_to_cpu(rp->current_settings); - print("\tcurrent settings: %s", settings2str(current_settings)); - - print("\tname %s", rp->name); - print("\tshort name %s", rp->short_name); - - if (supported_settings & MGMT_SETTING_CONFIGURATION) { - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, - index, 0, NULL, config_options_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_config cmd"); - goto done; - } - return; - } - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void ext_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_ext_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint32_t supported_settings, current_settings; - char addr[18]; - - if (status != 0) { - error("Reading hci%u info failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - print("hci%u:\tPrimary controller", index); - - ba2str(&rp->bdaddr, addr); - print("\taddr %s version %u manufacturer %u", - addr, rp->version, le16_to_cpu(rp->manufacturer)); - - supported_settings = le32_to_cpu(rp->supported_settings); - print("\tsupported settings: %s", settings2str(supported_settings)); - - current_settings = le32_to_cpu(rp->current_settings); - print("\tcurrent settings: %s", settings2str(current_settings)); - - if (supported_settings & MGMT_SETTING_CONFIGURATION) { - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, - index, 0, NULL, config_options_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_config cmd"); - goto done; - } - return; - } - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void index_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_index_list *rp = param; - struct mgmt *mgmt = user_data; - uint16_t count; - unsigned int i; - - if (status != 0) { - error("Reading index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small index list reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = le16_to_cpu(rp->num_controllers); - - if (len < sizeof(*rp) + count * sizeof(uint16_t)) { - error("Index count (%u) doesn't match reply length (%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Index list with %u item%s", count, count != 1 ? "s" : ""); - - for (i = 0; i < count; i++) { - uint16_t index = le16_to_cpu(rp->index[i]); - - if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, - info_rsp, UINT_TO_PTR(index), NULL)) { - error("Unable to send read_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - pending_index++; - } - - if (!count) - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_info(int argc, char **argv) -{ - if (mgmt_index == MGMT_INDEX_NONE) { - if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, - MGMT_INDEX_NONE, 0, NULL, - index_rsp, mgmt, NULL)) { - error("Unable to send index_list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - return; - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, mgmt_index, 0, NULL, info_rsp, - UINT_TO_PTR(mgmt_index), NULL)) { - error("Unable to send read_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void ext_index_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_ext_index_list *rp = param; - uint16_t count; - unsigned int i; - - if (status != 0) { - error("Reading ext index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small ext index list reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = get_le16(&rp->num_controllers); - - if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) { - error("Index count (%u) doesn't match reply length (%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Extended index list with %u item%s", - count, count != 1 ? "s" : ""); - - for (i = 0; i < count; i++) { - uint16_t index = le16_to_cpu(rp->entry[i].index); - char *busstr = hci_bustostr(rp->entry[i].bus); - - switch (rp->entry[i].type) { - case 0x00: - print("Primary controller (hci%u,%s)", index, busstr); - if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INFO, - index, 0, NULL, ext_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_ext_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - pending_index++; - break; - case 0x01: - print("Unconfigured controller (hci%u,%s)", - index, busstr); - if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, - index, 0, NULL, config_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_config cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - pending_index++; - break; - case 0x02: - print("AMP controller (hci%u,%s)", index, busstr); - break; - default: - print("Type %u controller (hci%u,%s)", - rp->entry[i].type, index, busstr); - break; - } - } - - print(""); - - if (!count) - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_extinfo(int argc, char **argv) -{ - if (mgmt_index == MGMT_INDEX_NONE) { - if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST, - MGMT_INDEX_NONE, 0, NULL, - ext_index_rsp, mgmt, NULL)) { - error("Unable to send ext_index_list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - return; - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INFO, mgmt_index, 0, NULL, - ext_info_rsp, - UINT_TO_PTR(mgmt_index), NULL)) { - error("Unable to send ext_read_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void print_cap(const uint8_t *cap, uint16_t cap_len) -{ - uint16_t parsed = 0; - - while (parsed < cap_len - 1) { - uint8_t field_len = cap[0]; - - if (field_len == 0) - break; - - parsed += field_len + 1; - - if (parsed > cap_len) - break; - - switch (cap[1]) { - case 0x01: - print("\tFlags: 0x%02x", cap[2]); - break; - case 0x02: - print("\tMax Key Size (BR/EDR): %u", cap[2]); - break; - case 0x03: - print("\tMax Key Size (LE): %u", cap[2]); - break; - default: - print("\tType %u: %u byte%s", cap[1], field_len - 1, - (field_len - 1) == 1 ? "" : "s"); - break; - } - - cap += field_len + 1; - } -} - -static void sec_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_controller_cap *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - - if (status != 0) { - error("Reading hci%u security failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - print("Primary controller (hci%u)", index); - print("\tInfo length: %u", le16_to_cpu(rp->cap_len)); - print_cap(rp->cap, le16_to_cpu(rp->cap_len)); - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void sec_index_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_ext_index_list *rp = param; - uint16_t count; - unsigned int i; - - if (status != 0) { - error("Reading ext index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small ext index list reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = get_le16(&rp->num_controllers); - - if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) { - error("Index count (%u) doesn't match reply length (%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - for (i = 0; i < count; i++) { - uint16_t index = le16_to_cpu(rp->entry[i].index); - - if (rp->entry[i].type != 0x00) - continue; - - if (!mgmt_send(mgmt, MGMT_OP_READ_CONTROLLER_CAP, - index, 0, NULL, sec_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_security_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - pending_index++; - } - - if (!count) - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_secinfo(int argc, char **argv) -{ - if (mgmt_index == MGMT_INDEX_NONE) { - if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST, - MGMT_INDEX_NONE, 0, NULL, - sec_index_rsp, mgmt, NULL)) { - error("Unable to send ext_index_list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - return; - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_CONTROLLER_CAP, mgmt_index, 0, NULL, - sec_info_rsp, - UINT_TO_PTR(mgmt_index), NULL)) { - error("Unable to send read_security_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void exp_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_exp_features_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - - if (status != 0) { - error("Reading hci%u exp features failed with status 0x%02x (%s)", - index, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small info reply (%u bytes)", len); - goto done; - } - - if (index == MGMT_INDEX_NONE) - print("Global"); - else - print("Primary controller (hci%u)", index); - - print("\tNumber of experimental features: %u", - le16_to_cpu(rp->feature_count)); - -done: - pending_index--; - - if (pending_index > 0) - return; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void exp_index_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_ext_index_list *rp = param; - uint16_t count; - unsigned int i; - - if (status != 0) { - error("Reading ext index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small ext index list reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = get_le16(&rp->num_controllers); - - if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) { - error("Index count (%u) doesn't match reply length (%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - for (i = 0; i < count; i++) { - uint16_t index = le16_to_cpu(rp->entry[i].index); - - if (rp->entry[i].type != 0x00) - continue; - - if (!mgmt_send(mgmt, MGMT_OP_READ_EXP_FEATURES_INFO, - index, 0, NULL, exp_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read_exp_features_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - pending_index++; - } -} - -static void cmd_expinfo(int argc, char **argv) -{ - if (mgmt_index == MGMT_INDEX_NONE) { - if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST, - MGMT_INDEX_NONE, 0, NULL, - exp_index_rsp, mgmt, NULL)) { - error("Unable to send ext_index_list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_EXP_FEATURES_INFO, - MGMT_INDEX_NONE, 0, NULL, - exp_info_rsp, - UINT_TO_PTR(MGMT_INDEX_NONE), NULL)) { - error("Unable to send read_exp_features_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - pending_index++; - return; - } - - if (!mgmt_send(mgmt, MGMT_OP_READ_EXP_FEATURES_INFO, mgmt_index, - 0, NULL, exp_info_rsp, - UINT_TO_PTR(mgmt_index), NULL)) { - error("Unable to send read_exp_features_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void exp_debug_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set debug feature failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Debug feature successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_exp_debug(int argc, char **argv) -{ - /* d4992530-b9ec-469f-ab01-6c481c47da1c */ - static const uint8_t uuid[16] = { - 0x1c, 0xda, 0x47, 0x1c, 0x48, 0x6c, 0x01, 0xab, - 0x9f, 0x46, 0xec, 0xb9, 0x30, 0x25, 0x99, 0xd4, - }; - struct mgmt_cp_set_exp_feature cp; - uint8_t val; - - if (parse_setting(argc, argv, &val) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - memset(&cp, 0, sizeof(cp)); - memcpy(cp.uuid, uuid, 16); - cp.action = val; - - if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, mgmt_index, - sizeof(cp), &cp, exp_debug_rsp, NULL, NULL) == 0) { - error("Unable to send debug feature cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void exp_privacy_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set LL privacy feature failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("LL privacy feature successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_exp_privacy(int argc, char **argv) -{ - /* 15c0a148-c273-11ea-b3de-0242ac130004 */ - static const uint8_t uuid[16] = { - 0x04, 0x00, 0x13, 0xac, 0x42, 0x02, 0xde, 0xb3, - 0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15, - }; - struct mgmt_cp_set_exp_feature cp; - uint8_t val; - - if (parse_setting(argc, argv, &val) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - memset(&cp, 0, sizeof(cp)); - memcpy(cp.uuid, uuid, 16); - cp.action = val; - - if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, mgmt_index, - sizeof(cp), &cp, exp_privacy_rsp, NULL, NULL) == 0) { - error("Unable to send LL privacy feature cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void exp_quality_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set Quality Report feature failed: 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Quality Report feature successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_exp_quality(int argc, char **argv) -{ - /* 330859bc-7506-492d-9370-9a6f0614037f */ - static const uint8_t uuid[16] = { - 0x7f, 0x03, 0x14, 0x06, 0x6f, 0x9a, 0x70, 0x93, - 0x2d, 0x49, 0x06, 0x75, 0xbc, 0x59, 0x08, 0x33, - }; - struct mgmt_cp_set_exp_feature cp; - uint8_t val; - - if (mgmt_index == MGMT_INDEX_NONE) { - error("BQR feature requires a valid controller index"); - return; - } - - if (parse_setting(argc, argv, &val) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - if (val != 0 && val != 1) { - error("Invalid value %u", val); - return; - } - - memset(&cp, 0, sizeof(cp)); - memcpy(cp.uuid, uuid, 16); - cp.action = val; - - if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, mgmt_index, - sizeof(cp), &cp, exp_quality_rsp, NULL, NULL) == 0) { - error("Unable to send quality report feature cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void print_mgmt_tlv(void *data, void *user_data) -{ - const struct mgmt_tlv *entry = data; - char buf[256]; - - bin2hex(entry->value, entry->length, buf, sizeof(buf)); - print("Type: 0x%04x\tLength: %02hhu\tValue: %s", entry->type, - entry->length, buf); -} - -static void read_sysconfig_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - struct mgmt_tlv_list *tlv_list; - - if (status != 0) { - error("Read system configuration failed with status " - "0x%02x (%s)", status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - tlv_list = mgmt_tlv_list_load_from_buf(param, len); - if (!tlv_list) { - error("Unable to parse response of read system configuration"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - mgmt_tlv_list_foreach(tlv_list, print_mgmt_tlv, NULL); - mgmt_tlv_list_free(tlv_list); - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_read_sysconfig(int argc, char **argv) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_READ_DEF_SYSTEM_CONFIG, index, - 0, NULL, read_sysconfig_rsp, NULL, NULL)) { - error("Unable to send read system configuration cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static bool parse_mgmt_tlv(const char *input, uint16_t *type, uint8_t *length, - uint8_t *value) -{ - int i, value_starting_pos; - - if (sscanf(input, "%4hx:%1hhu:%n", type, length, - &value_starting_pos) < 2) { - return false; - } - - input += value_starting_pos; - - if (*length * 2 != strlen(input)) - return false; - - for (i = 0; i < *length; i++) { - if (sscanf(input + i * 2, "%2hhx", &value[i]) < 1) - return false; - } - - return true; -} - -static void set_sysconfig_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != MGMT_STATUS_SUCCESS) { - error("Could not set default system configuration with status " - "0x%02x (%s)", status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Set default system configuration success"); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static bool set_sysconfig(int argc, char **argv) -{ - struct mgmt_tlv_list *tlv_list = NULL; - int i; - uint16_t index, type; - uint8_t length; - uint8_t value[256] = {}; - bool success = false; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - tlv_list = mgmt_tlv_list_new(); - if (!tlv_list) { - error("tlv_list failed to init"); - goto failed; - } - - for (i = 0; i < argc; i++) { - if (!parse_mgmt_tlv(argv[i], &type, &length, value)) { - error("failed to parse"); - goto failed; - } - - if (!mgmt_tlv_add(tlv_list, type, length, value)) { - error("failed to add"); - goto failed; - } - } - - if (!mgmt_send_tlv(mgmt, MGMT_OP_SET_DEF_SYSTEM_CONFIG, index, - tlv_list, set_sysconfig_rsp, NULL, NULL)) { - error("Failed to send \"Set Default System Configuration\"" - " command"); - goto failed; - } - - success = true; - -failed: - if (tlv_list) - mgmt_tlv_list_free(tlv_list); - - return success; -} - -static void set_sysconfig_usage(void) -{ - bt_shell_usage(); - print("Parameters:\n\t-v ...\n" - "e.g.:\n\tset-sysconfig -v 001a:2:1234 001f:1:00"); -} - -static void cmd_set_sysconfig(int argc, char **argv) -{ - bool success = false; - - if (strcasecmp(argv[1], "-v") == 0 && argc > 2) { - argc -= 2; - argv += 2; - success = set_sysconfig(argc, argv); - } - - if (!success) { - set_sysconfig_usage(); - bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void auto_power_enable_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - uint16_t index = PTR_TO_UINT(user_data); - - print("Successfully enabled controller with index %u", index); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void auto_power_info_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_rp_read_info *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint32_t supported_settings, current_settings, missing_settings; - uint8_t val = 0x01; - - if (status) { - error("Reading info failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - supported_settings = le32_to_cpu(rp->supported_settings); - current_settings = le32_to_cpu(rp->current_settings); - missing_settings = current_settings ^ supported_settings; - - if (missing_settings & MGMT_SETTING_BREDR) - mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, sizeof(val), &val, - NULL, NULL, NULL); - - if (missing_settings & MGMT_SETTING_SSP) - mgmt_send(mgmt, MGMT_OP_SET_SSP, index, sizeof(val), &val, - NULL, NULL, NULL); - - if (missing_settings & MGMT_SETTING_LE) - mgmt_send(mgmt, MGMT_OP_SET_LE, index, sizeof(val), &val, - NULL, NULL, NULL); - - if (missing_settings & MGMT_SETTING_SECURE_CONN) - mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, - sizeof(val), &val, - NULL, NULL, NULL); - - if (missing_settings & MGMT_SETTING_BONDABLE) - mgmt_send(mgmt, MGMT_OP_SET_BONDABLE, index, sizeof(val), &val, - NULL, NULL, NULL); - - if (current_settings & MGMT_SETTING_POWERED) - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - - if (!mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, sizeof(val), &val, - auto_power_enable_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send set powerd cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void auto_power_index_evt(uint16_t index, uint16_t len, - const void *param, void *user_data) -{ - uint16_t index_filter = PTR_TO_UINT(user_data); - - if (index != index_filter) - return; - - print("New controller with index %u", index); - - if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, - auto_power_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void auto_power_index_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_rp_read_index_list *rp = param; - uint16_t index = PTR_TO_UINT(user_data); - uint16_t i, count; - bool found = false; - - if (status) { - error("Reading index list failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = le16_to_cpu(rp->num_controllers); - for (i = 0; i < count; i++) { - if (le16_to_cpu(rp->index[i]) == index) - found = true; - } - - if (!found) { - print("Waiting for index %u to appear", index); - - mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, - auto_power_index_evt, - UINT_TO_PTR(index), NULL); - return; - } - - print("Found controller with index %u", index); - - if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, - auto_power_info_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_auto_power(int argc, char **argv) -{ - int index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, - auto_power_index_rsp, - UINT_TO_PTR(index), NULL)) { - error("Unable to send read index list cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void get_flags_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_device_flags *rp = param; - - if (status != 0) { - error("Get device flags failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Supported Flags: 0x%08x", rp->supported_flags); - print("Current Flags: 0x%08x", rp->current_flags); - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option get_flags_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_get_flags(int argc, char **argv) -{ - struct mgmt_cp_get_device_flags cp; - uint8_t type = BDADDR_BREDR; - char addr[18]; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", get_flags_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 < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - ba2str(&cp.addr.bdaddr, addr); - print("Get device flag of %s (%s)", addr, typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_GET_DEVICE_FLAGS, index, sizeof(cp), &cp, - get_flags_rsp, NULL, NULL) == 0) { - error("Unable to send Get Device Flags command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void set_flags_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Set device flags failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - bt_shell_noninteractive_quit(EXIT_FAILURE); - } - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option set_flags_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { "flags", 1, 0, 'f' }, - { 0, 0, 0, 0 } -}; - -static void cmd_set_flags(int argc, char **argv) -{ - struct mgmt_cp_set_device_flags cp; - uint8_t type = BDADDR_BREDR; - uint32_t flags = 0; - char addr[18]; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+f:t:h", set_flags_options, - NULL)) != -1) { - switch (opt) { - case 'f': - flags = strtol(optarg, NULL, 0); - break; - 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 < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - cp.current_flags = flags; - - ba2str(&cp.addr.bdaddr, addr); - print("Set device flag of %s (%s)", addr, typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_FLAGS, index, sizeof(cp), &cp, - set_flags_rsp, NULL, NULL) == 0) { - error("Unable to send Set Device Flags 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; - uint16_t op; - void (*callback) (uint16_t id, uint16_t op, uint8_t status, - uint16_t len, const void *param); -}; - -static void cmd_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - struct command_data *data = user_data; - - data->callback(data->op, data->id, status, len, param); -} - -static unsigned int send_cmd(struct mgmt *mgmt, uint16_t op, uint16_t id, - uint16_t len, const void *param, - void (*cb)(uint16_t id, uint16_t op, - uint8_t status, uint16_t len, - const void *param)) -{ - struct command_data *data; - unsigned int send_id; - - data = new0(struct command_data, 1); - if (!data) - return 0; - - data->id = id; - data->op = op; - data->callback = cb; - - send_id = mgmt_send(mgmt, op, id, len, param, cmd_rsp, data, free); - if (send_id == 0) - free(data); - - return send_id; -} - -static void setting_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, - const void *param) -{ - const uint32_t *rp = param; - - if (status != 0) { - error("%s for hci%u failed with status 0x%02x (%s)", - mgmt_opstr(op), id, status, mgmt_errstr(status)); - goto done; - } - - if (len < sizeof(*rp)) { - error("Too small %s response (%u bytes)", - mgmt_opstr(op), len); - goto done; - } - - print("hci%u %s complete, settings: %s", id, mgmt_opstr(op), - settings2str(get_le32(rp))); - -done: - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_setting(uint16_t op, int argc, char **argv) -{ - int index; - uint8_t val; - - if (parse_setting(argc, argv, &val) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (send_cmd(mgmt, op, index, sizeof(val), &val, setting_rsp) == 0) { - error("Unable to send %s cmd", mgmt_opstr(op)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_power(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_POWERED, argc, argv); -} - -static void cmd_discov(int argc, char **argv) -{ - struct mgmt_cp_set_discoverable cp; - uint16_t index; - - memset(&cp, 0, sizeof(cp)); - - if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) - cp.val = 1; - else if (strcasecmp(argv[1], "off") == 0) - cp.val = 0; - else if (strcasecmp(argv[1], "limited") == 0) - cp.val = 2; - else - cp.val = atoi(argv[1]); - - if (argc > 2) - cp.timeout = htobs(atoi(argv[2])); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (send_cmd(mgmt, MGMT_OP_SET_DISCOVERABLE, index, sizeof(cp), &cp, - setting_rsp) == 0) { - error("Unable to send set_discoverable cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_connectable(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_CONNECTABLE, argc, argv); -} - -static void cmd_fast_conn(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_FAST_CONNECTABLE, argc, argv); -} - -static void cmd_bondable(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_BONDABLE, argc, argv); -} - -static void cmd_linksec(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_LINK_SECURITY, argc, argv); -} - -static void cmd_ssp(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_SSP, argc, argv); -} - -static void cmd_sc(int argc, char **argv) -{ - uint8_t val; - uint16_t index; - - if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) - val = 1; - else if (strcasecmp(argv[1], "off") == 0) - val = 0; - else if (strcasecmp(argv[1], "only") == 0) - val = 2; - else - val = atoi(argv[1]); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (send_cmd(mgmt, MGMT_OP_SET_SECURE_CONN, index, - sizeof(val), &val, setting_rsp) == 0) { - error("Unable to send set_secure_conn cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_hs(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_HS, argc, argv); -} - -static void cmd_le(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_LE, argc, argv); -} - -static void cmd_advertising(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_ADVERTISING, argc, argv); -} - -static void cmd_bredr(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_BREDR, argc, argv); -} - -static void cmd_privacy(int argc, char **argv) -{ - struct mgmt_cp_set_privacy cp; - uint16_t index; - - if (parse_setting(argc, argv, &cp.privacy) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (argc > 2) { - if (hex2bin(argv[2], cp.irk, - sizeof(cp.irk)) != sizeof(cp.irk)) { - error("Invalid key format"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } else { - int fd; - - fd = open("/dev/urandom", O_RDONLY); - if (fd < 0) { - error("open(/dev/urandom): %s", strerror(errno)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (read(fd, cp.irk, sizeof(cp.irk)) != sizeof(cp.irk)) { - error("Reading from urandom failed"); - close(fd); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - close(fd); - } - - if (send_cmd(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp, - setting_rsp) == 0) { - error("Unable to send Set Privacy command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void exp_offload_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set offload codec failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Offload codec feature successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_exp_offload_codecs(int argc, char **argv) -{ - /* a6695ace-ee7f-4fb9-881a-5fac66c629af */ - static const uint8_t uuid[16] = { - 0xaf, 0x29, 0xc6, 0x66, 0xac, 0x5f, 0x1a, 0x88, - 0xb9, 0x4f, 0x7f, 0xee, 0xce, 0x5a, 0x69, 0xa6, - }; - - struct mgmt_cp_set_exp_feature cp; - uint8_t val; - uint16_t index; - - if (parse_setting(argc, argv, &val) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - memcpy(cp.uuid, uuid, 16); - cp.action = val; - - if (mgmt_send(mgmt, MGMT_OP_SET_EXP_FEATURE, index, - sizeof(cp), &cp, exp_offload_rsp, NULL, NULL) == 0) { - error("Unable to send offload codecs feature cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void class_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, - const void *param) -{ - const struct mgmt_ev_class_of_dev_changed *rp = param; - - if (len == 0 && status != 0) { - error("%s failed, status 0x%02x (%s)", - mgmt_opstr(op), status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Unexpected %s len %u", mgmt_opstr(op), len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("%s succeeded. Class 0x%02x%02x%02x", mgmt_opstr(op), - rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_class(int argc, char **argv) -{ - uint8_t class[2]; - uint16_t index; - - class[0] = atoi(argv[1]); - class[1] = atoi(argv[2]); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (send_cmd(mgmt, MGMT_OP_SET_DEV_CLASS, index, sizeof(class), class, - class_rsp) == 0) { - error("Unable to send set_dev_class cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void disconnect_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_disconnect *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("Disconnect failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Invalid disconnect response length (%u)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->addr.bdaddr, addr); - - if (status == 0) - print("%s disconnected", addr); - else - error("Disconnecting %s failed with status 0x%02x (%s)", - addr, status, mgmt_errstr(status)); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option disconnect_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_disconnect(int argc, char **argv) -{ - struct mgmt_cp_disconnect cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", disconnect_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); - } - } - - argv += optind; - optind = 0; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - if (mgmt_send(mgmt, MGMT_OP_DISCONNECT, index, sizeof(cp), &cp, - disconnect_rsp, NULL, NULL) == 0) { - error("Unable to send disconnect cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void con_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_connections *rp = param; - uint16_t count, i; - - if (len < sizeof(*rp)) { - error("Too small (%u bytes) get_connections rsp", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - count = get_le16(&rp->conn_count); - if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) { - error("Invalid get_connections length (count=%u, len=%u)", - count, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - for (i = 0; i < count; i++) { - char addr[18]; - - ba2str(&rp->addr[i].bdaddr, addr); - - print("%s type %s", addr, typestr(rp->addr[i].type)); - } - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_con(int argc, char **argv) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (mgmt_send(mgmt, MGMT_OP_GET_CONNECTIONS, index, 0, NULL, - con_rsp, NULL, NULL) == 0) { - error("Unable to send get_connections cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void find_service_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Start Service Discovery failed: status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Service discovery started"); - discovery = true; -} - -static struct option find_service_options[] = { - { "help", no_argument, 0, 'h' }, - { "le-only", no_argument, 0, 'l' }, - { "bredr-only", no_argument, 0, 'b' }, - { "uuid", required_argument, 0, 'u' }, - { "rssi", required_argument, 0, 'r' }, - { 0, 0, 0, 0 } -}; - -static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid) -{ - if (uuid->type == SDP_UUID16) - sdp_uuid16_to_uuid128(uuid128, uuid); - else if (uuid->type == SDP_UUID32) - sdp_uuid32_to_uuid128(uuid128, uuid); - else - memcpy(uuid128, uuid, sizeof(*uuid)); -} - -#define MAX_UUIDS 4 - -static void cmd_find_service(int argc, char **argv) -{ - struct mgmt_cp_start_service_discovery *cp; - uint8_t buf[sizeof(*cp) + 16 * MAX_UUIDS]; - uuid_t uuid; - uint128_t uint128; - uuid_t uuid128; - uint8_t type = SCAN_TYPE_DUAL; - int8_t rssi; - uint16_t count; - int opt; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - rssi = 127; - count = 0; - - while ((opt = getopt_long(argc, argv, "+lbu:r:h", - find_service_options, NULL)) != -1) { - switch (opt) { - case 'l': - type &= ~SCAN_TYPE_BREDR; - type |= SCAN_TYPE_LE; - break; - case 'b': - type |= SCAN_TYPE_BREDR; - type &= ~SCAN_TYPE_LE; - break; - case 'u': - if (count == MAX_UUIDS) { - print("Max %u UUIDs supported", MAX_UUIDS); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (bt_string2uuid(&uuid, optarg) < 0) { - print("Invalid UUID: %s", optarg); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - cp = (void *) buf; - uuid_to_uuid128(&uuid128, &uuid); - ntoh128((uint128_t *) uuid128.value.uuid128.data, - &uint128); - htob128(&uint128, (uint128_t *) cp->uuids[count++]); - break; - case 'r': - rssi = atoi(optarg); - 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); - } - } - - optind = 0; - - cp = (void *) buf; - cp->type = type; - cp->rssi = rssi; - cp->uuid_count = cpu_to_le16(count); - - if (mgmt_send(mgmt, MGMT_OP_START_SERVICE_DISCOVERY, index, - sizeof(*cp) + count * 16, cp, - find_service_rsp, NULL, NULL) == 0) { - error("Unable to send start_service_discovery cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void find_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Unable to start discovery. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Discovery started"); - discovery = true; -} - -static struct option find_options[] = { - { "help", 0, 0, 'h' }, - { "le-only", 1, 0, 'l' }, - { "bredr-only", 1, 0, 'b' }, - { "limited", 1, 0, 'L' }, - { 0, 0, 0, 0 } -}; - -static void cmd_find(int argc, char **argv) -{ - struct mgmt_cp_start_discovery cp; - uint8_t op = MGMT_OP_START_DISCOVERY; - uint8_t type = SCAN_TYPE_DUAL; - int opt; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - while ((opt = getopt_long(argc, argv, "+lbLh", find_options, - NULL)) != -1) { - switch (opt) { - case 'l': - type &= ~SCAN_TYPE_BREDR; - type |= SCAN_TYPE_LE; - break; - case 'b': - type |= SCAN_TYPE_BREDR; - type &= ~SCAN_TYPE_LE; - break; - case 'L': - op = MGMT_OP_START_LIMITED_DISCOVERY; - 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); - } - } - - optind = 0; - - memset(&cp, 0, sizeof(cp)); - cp.type = type; - - if (mgmt_send(mgmt, op, index, sizeof(cp), &cp, find_rsp, - NULL, NULL) == 0) { - error("Unable to send start_discovery cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void stop_find_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Stop Discovery failed: status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - } - - print("Discovery stopped"); - discovery = false; - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option stop_find_options[] = { - { "help", 0, 0, 'h' }, - { "le-only", 1, 0, 'l' }, - { "bredr-only", 1, 0, 'b' }, - { 0, 0, 0, 0 } -}; - -static void cmd_stop_find(int argc, char **argv) -{ - struct mgmt_cp_stop_discovery cp; - uint8_t type = SCAN_TYPE_DUAL; - int opt; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - while ((opt = getopt_long(argc, argv, "+lbh", stop_find_options, - NULL)) != -1) { - switch (opt) { - case 'l': - type &= ~SCAN_TYPE_BREDR; - type |= SCAN_TYPE_LE; - break; - case 'b': - type |= SCAN_TYPE_BREDR; - type &= ~SCAN_TYPE_LE; - break; - case 'h': - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - } - } - - optind = 0; - - memset(&cp, 0, sizeof(cp)); - cp.type = type; - - if (mgmt_send(mgmt, MGMT_OP_STOP_DISCOVERY, index, sizeof(cp), &cp, - stop_find_rsp, NULL, NULL) == 0) { - error("Unable to send stop_discovery cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void name_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Unable to set local name with status 0x%02x (%s)", - status, mgmt_errstr(status)); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_name(int argc, char **argv) -{ - struct mgmt_cp_set_local_name cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH); - if (argc > 2) - strncpy((char *) cp.short_name, argv[2], - MGMT_MAX_SHORT_NAME_LENGTH - 1); - - if (mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, index, sizeof(cp), &cp, - name_rsp, NULL, NULL) == 0) { - error("Unable to send set_name cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void pair_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_pair_device *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("Pairing failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Unexpected pair_rsp len %u", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->addr.bdaddr, addr); - - if (status) - error("Pairing with %s (%s) failed. status 0x%02x (%s)", - addr, typestr(rp->addr.type), status, - mgmt_errstr(status)); - else - print("Paired with %s (%s)", addr, typestr(rp->addr.type)); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option pair_options[] = { - { "help", 0, 0, 'h' }, - { "capability", 1, 0, 'c' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_pair(int argc, char **argv) -{ - struct mgmt_cp_pair_device cp; - uint8_t cap = 0x01; - uint8_t type = BDADDR_BREDR; - char addr[18]; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options, - NULL)) != -1) { - switch (opt) { - case 'c': - cap = strtol(optarg, NULL, 0); - break; - 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 < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - cp.io_cap = cap; - - ba2str(&cp.addr.bdaddr, addr); - print("Pairing with %s (%s)", addr, typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp, - pair_rsp, NULL, NULL) == 0) { - error("Unable to send pair_device cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cancel_pair_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_addr_info *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("Cancel Pairing failed with 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Unexpected cancel_pair_rsp len %u", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->bdaddr, addr); - - if (status) - error("Cancel Pairing with %s (%s) failed. 0x%02x (%s)", - addr, typestr(rp->type), status, - mgmt_errstr(status)); - else - print("Pairing Cancelled with %s", addr); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option cancel_pair_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_cancel_pair(int argc, char **argv) -{ - struct mgmt_addr_info cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", cancel_pair_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 < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.bdaddr); - cp.type = type; - - if (mgmt_reply(mgmt, MGMT_OP_CANCEL_PAIR_DEVICE, index, sizeof(cp), &cp, - cancel_pair_rsp, NULL, NULL) == 0) { - error("Unable to send cancel_pair_device cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void unpair_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_unpair_device *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("Unpair device failed. status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Unexpected unpair_device_rsp len %u", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->addr.bdaddr, addr); - - if (status) - error("Unpairing %s failed. status 0x%02x (%s)", - addr, status, mgmt_errstr(status)); - else - print("%s unpaired", addr); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option unpair_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_unpair(int argc, char **argv) -{ - struct mgmt_cp_unpair_device cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", unpair_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 < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - cp.disconnect = 1; - - if (mgmt_send(mgmt, MGMT_OP_UNPAIR_DEVICE, index, sizeof(cp), &cp, - unpair_rsp, NULL, NULL) == 0) { - error("Unable to send unpair_device cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void keys_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Load keys failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Keys successfully loaded"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_keys(int argc, char **argv) -{ - struct mgmt_cp_load_link_keys cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - - if (mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index, sizeof(cp), &cp, - keys_rsp, NULL, NULL) == 0) { - error("Unable to send load_keys cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void ltks_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Load keys failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Long term keys successfully loaded"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_ltks(int argc, char **argv) -{ - struct mgmt_cp_load_long_term_keys cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - - if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index, sizeof(cp), &cp, - ltks_rsp, NULL, NULL) == 0) { - error("Unable to send load_ltks cmd"); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - } -} - -static void irks_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Load IRKs failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Identity Resolving Keys successfully loaded"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option irks_options[] = { - { "help", 0, 0, 'h' }, - { "local", 1, 0, 'l' }, - { "file", 1, 0, 'f' }, - { 0, 0, 0, 0 } -}; - -#define MAX_IRKS 4 - -static void cmd_irks(int argc, char **argv) -{ - struct mgmt_cp_load_irks *cp; - uint8_t buf[sizeof(*cp) + 23 * MAX_IRKS]; - uint16_t count, local_index; - char path[PATH_MAX]; - int opt; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp = (void *) buf; - count = 0; - - while ((opt = getopt_long(argc, argv, "+l:f:h", - irks_options, NULL)) != -1) { - switch (opt) { - case 'l': - if (count >= MAX_IRKS) { - error("Number of IRKs exceeded"); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - if (strlen(optarg) > 3 && - strncasecmp(optarg, "hci", 3) == 0) - local_index = atoi(optarg + 3); - else - local_index = atoi(optarg); - snprintf(path, sizeof(path), - "/sys/kernel/debug/bluetooth/hci%u/identity", - local_index); - if (!load_identity(path, &cp->irks[count])) { - error("Unable to load identity"); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - count++; - break; - case 'f': - if (count >= MAX_IRKS) { - error("Number of IRKs exceeded"); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - if (!load_identity(optarg, &cp->irks[count])) { - error("Unable to load identities"); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - count++; - 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); - } - } - - optind = 0; - - cp->irk_count = cpu_to_le16(count); - - if (mgmt_send(mgmt, MGMT_OP_LOAD_IRKS, index, - sizeof(*cp) + count * 23, cp, - irks_rsp, NULL, NULL) == 0) { - error("Unable to send load_irks cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void block_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len, - const void *param) -{ - const struct mgmt_addr_info *rp = param; - char addr[18]; - - if (len == 0 && status != 0) { - error("%s failed, status 0x%02x (%s)", - mgmt_opstr(op), status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Unexpected %s len %u", mgmt_opstr(op), len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->bdaddr, addr); - - if (status) - error("%s %s (%s) failed. status 0x%02x (%s)", - mgmt_opstr(op), addr, typestr(rp->type), - status, mgmt_errstr(status)); - else - print("%s %s succeeded", mgmt_opstr(op), addr); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option block_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_block(int argc, char **argv) -{ - struct mgmt_cp_block_device cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", block_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 < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - if (send_cmd(mgmt, MGMT_OP_BLOCK_DEVICE, index, sizeof(cp), &cp, - block_rsp) == 0) { - error("Unable to send block_device cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_unblock(int argc, char **argv) -{ - struct mgmt_cp_unblock_device cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", block_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 < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - if (send_cmd(mgmt, MGMT_OP_UNBLOCK_DEVICE, index, sizeof(cp), &cp, - block_rsp) == 0) { - error("Unable to send unblock_device cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_add_uuid(int argc, char **argv) -{ - struct mgmt_cp_add_uuid cp; - uint128_t uint128; - uuid_t uuid, uuid128; - uint16_t index; - - if (argc < 3) { - print("UUID and service hint needed"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (bt_string2uuid(&uuid, argv[1]) < 0) { - print("Invalid UUID: %s", argv[1]); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - memset(&cp, 0, sizeof(cp)); - - uuid_to_uuid128(&uuid128, &uuid); - ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128); - htob128(&uint128, (uint128_t *) cp.uuid); - - cp.svc_hint = atoi(argv[2]); - - if (send_cmd(mgmt, MGMT_OP_ADD_UUID, index, sizeof(cp), &cp, - class_rsp) == 0) { - error("Unable to send add_uuid cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_remove_uuid(int argc, char **argv) -{ - struct mgmt_cp_remove_uuid cp; - uint128_t uint128; - uuid_t uuid, uuid128; - uint16_t index; - - if (argc < 2) { - print("UUID needed"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (bt_string2uuid(&uuid, argv[1]) < 0) { - print("Invalid UUID: %s", argv[1]); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - memset(&cp, 0, sizeof(cp)); - - uuid_to_uuid128(&uuid128, &uuid); - ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128); - htob128(&uint128, (uint128_t *) cp.uuid); - - if (send_cmd(mgmt, MGMT_OP_REMOVE_UUID, index, sizeof(cp), &cp, - class_rsp) == 0) { - error("Unable to send remove_uuid cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_clr_uuids(int argc, char **argv) -{ - char *uuid_any = "00000000-0000-0000-0000-000000000000"; - char *rm_argv[] = { "rm-uuid", uuid_any, NULL }; - - cmd_remove_uuid(2, rm_argv); -} - -static void local_oob_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_local_oob_data *rp = param; - char str[33]; - - if (status != 0) { - error("Read Local OOB Data failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small (%u bytes) read_local_oob rsp", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - bin2hex(rp->hash192, 16, str, sizeof(str)); - print("Hash C from P-192: %s", str); - - bin2hex(rp->rand192, 16, str, sizeof(str)); - print("Randomizer R with P-192: %s", str); - - if (len < sizeof(*rp)) - return bt_shell_noninteractive_quit(EXIT_SUCCESS); - - bin2hex(rp->hash256, 16, str, sizeof(str)); - print("Hash C from P-256: %s", str); - - bin2hex(rp->rand256, 16, str, sizeof(str)); - print("Randomizer R with P-256: %s", str); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_local_oob(int argc, char **argv) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL, - local_oob_rsp, NULL, NULL) == 0) { - error("Unable to send read_local_oob cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void remote_oob_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_addr_info *rp = param; - char addr[18]; - - if (status != 0) { - error("Add Remote OOB Data failed: 0x%02x (%s)", - status, mgmt_errstr(status)); - return; - } - - if (len < sizeof(*rp)) { - error("Too small (%u bytes) add_remote_oob rsp", len); - return; - } - - ba2str(&rp->bdaddr, addr); - print("Remote OOB data added for %s (%u)", addr, rp->type); -} - -static struct option remote_oob_opt[] = { - { "help", 0, 0, '?' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_remote_oob(int argc, char **argv) -{ - struct mgmt_cp_add_remote_oob_data cp; - int opt; - uint16_t index; - - memset(&cp, 0, sizeof(cp)); - cp.addr.type = BDADDR_BREDR; - - while ((opt = getopt_long(argc, argv, "+t:r:R:h:H:", - remote_oob_opt, NULL)) != -1) { - switch (opt) { - case 't': - cp.addr.type = strtol(optarg, NULL, 0); - break; - case 'r': - hex2bin(optarg, cp.rand192, 16); - break; - case 'h': - hex2bin(optarg, cp.hash192, 16); - break; - case 'R': - hex2bin(optarg, cp.rand256, 16); - break; - case 'H': - hex2bin(optarg, cp.hash256, 16); - break; - default: - bt_shell_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - str2ba(argv[0], &cp.addr.bdaddr); - - print("Adding OOB data for %s (%s)", argv[0], typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA, index, - sizeof(cp), &cp, remote_oob_rsp, - NULL, NULL) == 0) { - error("Unable to send add_remote_oob cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void did_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set Device ID failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Device ID successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_did(int argc, char **argv) -{ - struct mgmt_cp_set_device_id cp; - uint16_t vendor, product, version , source; - int result; - uint16_t index; - - result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product, - &version); - if (result == 3) { - source = 0x0001; - goto done; - } - - result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product, - &version); - if (result == 3) { - source = 0x0002; - goto done; - } - - return; -done: - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp.source = htobs(source); - cp.vendor = htobs(vendor); - cp.product = htobs(product); - cp.version = htobs(version); - - if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_ID, index, sizeof(cp), &cp, - did_rsp, NULL, NULL) == 0) { - error("Unable to send set_device_id cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void static_addr_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set static address failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Static address successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_static_addr(int argc, char **argv) -{ - struct mgmt_cp_set_static_address cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - str2ba(argv[1], &cp.bdaddr); - - if (mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, sizeof(cp), &cp, - static_addr_rsp, NULL, NULL) == 0) { - error("Unable to send set_static_address cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void options_rsp(uint16_t op, uint16_t id, uint8_t status, - uint16_t len, const void *param) -{ - const uint32_t *rp = param; - - if (status != 0) { - error("%s for hci%u failed with status 0x%02x (%s)", - mgmt_opstr(op), id, status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small %s response (%u bytes)", - mgmt_opstr(op), len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("hci%u %s complete, options: %s", id, mgmt_opstr(op), - options2str(get_le32(rp))); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_public_addr(int argc, char **argv) -{ - struct mgmt_cp_set_public_address cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - str2ba(argv[1], &cp.bdaddr); - - if (send_cmd(mgmt, MGMT_OP_SET_PUBLIC_ADDRESS, index, sizeof(cp), &cp, - options_rsp) == 0) { - error("Unable to send Set Public Address cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_ext_config(int argc, char **argv) -{ - struct mgmt_cp_set_external_config cp; - uint16_t index; - - if (parse_setting(argc, argv, &cp.config) == false) - return bt_shell_noninteractive_quit(EXIT_FAILURE); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (send_cmd(mgmt, MGMT_OP_SET_EXTERNAL_CONFIG, index, sizeof(cp), &cp, - options_rsp) == 0) { - error("Unable to send Set External Config cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_debug_keys(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_DEBUG_KEYS, argc, argv); -} - -static void conn_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_conn_info *rp = param; char addr[18]; - - if (len == 0 && status != 0) { - error("Get Conn Info failed, status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Unexpected Get Conn Info len %u", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - ba2str(&rp->addr.bdaddr, addr); - - if (status) { - error("Get Conn Info for %s (%s) failed. status 0x%02x (%s)", - addr, typestr(rp->addr.type), - status, mgmt_errstr(status)); - } else { - print("Connection Information for %s (%s)", - addr, typestr(rp->addr.type)); - print("\tRSSI %d\tTX power %d\tmaximum TX power %d", - rp->rssi, rp->tx_power, rp->max_tx_power); - } - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option conn_info_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_conn_info(int argc, char **argv) -{ - struct mgmt_cp_get_conn_info cp; - uint8_t type = BDADDR_BREDR; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", conn_info_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 < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - if (mgmt_send(mgmt, MGMT_OP_GET_CONN_INFO, index, sizeof(cp), &cp, - conn_info_rsp, NULL, NULL) == 0) { - error("Unable to send get_conn_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void io_cap_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Could not set IO Capability with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("IO Capabilities successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_io_cap(int argc, char **argv) -{ - struct mgmt_cp_set_io_capability cp; - uint8_t cap; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cap = strtol(argv[1], NULL, 0); - memset(&cp, 0, sizeof(cp)); - cp.io_capability = cap; - - if (mgmt_send(mgmt, MGMT_OP_SET_IO_CAPABILITY, index, sizeof(cp), &cp, - io_cap_rsp, NULL, NULL) == 0) { - error("Unable to send set-io-cap cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void scan_params_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Set scan parameters failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Scan parameters successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_scan_params(int argc, char **argv) -{ - struct mgmt_cp_set_scan_params cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp.interval = strtol(argv[1], NULL, 0); - cp.window = strtol(argv[2], NULL, 0); - - if (mgmt_send(mgmt, MGMT_OP_SET_SCAN_PARAMS, index, sizeof(cp), &cp, - scan_params_rsp, NULL, NULL) == 0) { - error("Unable to send set_scan_params cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void clock_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_clock_info *rp = param; - - if (len < sizeof(*rp)) { - error("Unexpected Get Clock Info len %u", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (status) { - error("Get Clock Info failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Local Clock: %u", le32_to_cpu(rp->local_clock)); - print("Piconet Clock: %u", le32_to_cpu(rp->piconet_clock)); - print("Accurary: %u", le16_to_cpu(rp->accuracy)); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_clock_info(int argc, char **argv) -{ - struct mgmt_cp_get_clock_info cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - - if (argc > 1) - str2ba(argv[1], &cp.addr.bdaddr); - - if (mgmt_send(mgmt, MGMT_OP_GET_CLOCK_INFO, index, sizeof(cp), &cp, - clock_info_rsp, NULL, NULL) == 0) { - error("Unable to send get_clock_info cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void add_device_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Add device failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option add_device_options[] = { - { "help", 0, 0, 'h' }, - { "action", 1, 0, 'a' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_add_device(int argc, char **argv) -{ - struct mgmt_cp_add_device cp; - uint8_t action = 0x00; - uint8_t type = BDADDR_BREDR; - char addr[18]; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+a:t:h", add_device_options, - NULL)) != -1) { - switch (opt) { - case 'a': - action = strtol(optarg, NULL, 0); - break; - 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 < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - cp.action = action; - - ba2str(&cp.addr.bdaddr, addr); - print("Adding device with %s (%s)", addr, typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_ADD_DEVICE, index, sizeof(cp), &cp, - add_device_rsp, NULL, NULL) == 0) { - error("Unable to send add device command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void remove_device_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Remove device failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static struct option del_device_options[] = { - { "help", 0, 0, 'h' }, - { "type", 1, 0, 't' }, - { 0, 0, 0, 0 } -}; - -static void cmd_del_device(int argc, char **argv) -{ - struct mgmt_cp_remove_device cp; - uint8_t type = BDADDR_BREDR; - char addr[18]; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+t:h", del_device_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 < 1) { - bt_shell_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - str2ba(argv[0], &cp.addr.bdaddr); - cp.addr.type = type; - - ba2str(&cp.addr.bdaddr, addr); - print("Removing device with %s (%s)", addr, typestr(cp.addr.type)); - - if (mgmt_send(mgmt, MGMT_OP_REMOVE_DEVICE, index, sizeof(cp), &cp, - remove_device_rsp, NULL, NULL) == 0) { - error("Unable to send remove device command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_clr_devices(int argc, char **argv) -{ - char *bdaddr_any = "00:00:00:00:00:00"; - char *rm_argv[] = { "del-device", bdaddr_any, NULL }; - - cmd_del_device(2, rm_argv); -} - -static void local_oob_ext_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_local_oob_ext_data *rp = param; - uint16_t eir_len; - - if (status != 0) { - error("Read Local OOB Ext Data failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small (%u bytes) read_local_oob_ext rsp", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - eir_len = le16_to_cpu(rp->eir_len); - if (len != sizeof(*rp) + eir_len) { - error("local_oob_ext: expected %zu bytes, got %u bytes", - sizeof(*rp) + eir_len, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print_eir(rp->eir, eir_len); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_bredr_oob(int argc, char **argv) -{ - struct mgmt_cp_read_local_oob_ext_data cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp.type = SCAN_TYPE_BREDR; - - if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, - index, sizeof(cp), &cp, - local_oob_ext_rsp, NULL, NULL)) { - error("Unable to send read_local_oob_ext cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_le_oob(int argc, char **argv) -{ - struct mgmt_cp_read_local_oob_ext_data cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp.type = SCAN_TYPE_LE; - - if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, - index, sizeof(cp), &cp, - local_oob_ext_rsp, NULL, NULL)) { - error("Unable to send read_local_oob_ext cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static const char *adv_flags_str[] = { - "connectable", - "general-discoverable", - "limited-discoverable", - "managed-flags", - "tx-power", - "scan-rsp-appearance", - "scan-rsp-local-name", - "Secondary-channel-1M", - "Secondary-channel-2M", - "Secondary-channel-CODED", -}; - -static const char *adv_flags2str(uint32_t flags) -{ - static char str[256]; - unsigned i; - int off; - - off = 0; - str[0] = '\0'; - - for (i = 0; i < NELEM(adv_flags_str); i++) { - if ((flags & (1 << i)) != 0) - off += snprintf(str + off, sizeof(str) - off, "%s ", - adv_flags_str[i]); - } - - return str; -} - -static void adv_features_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_adv_features *rp = param; - uint32_t supported_flags; - - if (status != 0) { - error("Reading adv features failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small adv features reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp) + rp->num_instances * sizeof(uint8_t)) { - error("Instances count (%u) doesn't match reply length (%u)", - rp->num_instances, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - supported_flags = le32_to_cpu(rp->supported_flags); - print("Supported flags: %s", adv_flags2str(supported_flags)); - print("Max advertising data len: %u", rp->max_adv_data_len); - print("Max scan response data len: %u", rp->max_scan_rsp_len); - print("Max instances: %u", rp->max_instances); - - print("Instances list with %u item%s", rp->num_instances, - rp->num_instances != 1 ? "s" : ""); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_advinfo(int argc, char **argv) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_READ_ADV_FEATURES, index, 0, NULL, - adv_features_rsp, NULL, NULL)) { - error("Unable to send advertising features command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void adv_size_info_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_adv_size_info *rp = param; - uint32_t flags; - - if (status != 0) { - error("Reading adv size info failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small adv size info reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - flags = le32_to_cpu(rp->flags); - print("Instance: %u", rp->instance); - print("Flags: %s", adv_flags2str(flags)); - print("Max advertising data len: %u", rp->max_adv_data_len); - print("Max scan response data len: %u", rp->max_scan_rsp_len); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void advsize_usage(void) -{ - bt_shell_usage(); - print("Options:\n" - "\t -c, --connectable \"connectable\" flag\n" - "\t -g, --general-discov \"general-discoverable\" flag\n" - "\t -l, --limited-discov \"limited-discoverable\" flag\n" - "\t -m, --managed-flags \"managed-flags\" flag\n" - "\t -p, --tx-power \"tx-power\" flag\n" - "\t -a, --appearance \"appearance\" flag\n" - "\t -n, --local-name \"local-name\" flag"); -} - -static struct option advsize_options[] = { - { "help", 0, 0, 'h' }, - { "connectable", 0, 0, 'c' }, - { "general-discov", 0, 0, 'g' }, - { "limited-discov", 0, 0, 'l' }, - { "managed-flags", 0, 0, 'm' }, - { "tx-power", 0, 0, 'p' }, - { "appearance", 0, 0, 'a' }, - { "local-name", 0, 0, 'n' }, - { 0, 0, 0, 0} -}; - -static void cmd_advsize(int argc, char **argv) -{ - struct mgmt_cp_get_adv_size_info cp; - uint8_t instance; - uint32_t flags = 0; - int opt; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+cglmphna", - advsize_options, NULL)) != -1) { - switch (opt) { - case 'c': - flags |= MGMT_ADV_FLAG_CONNECTABLE; - break; - case 'g': - flags |= MGMT_ADV_FLAG_DISCOV; - break; - case 'l': - flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; - break; - case 'm': - flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; - break; - case 'p': - flags |= MGMT_ADV_FLAG_TX_POWER; - break; - case 'a': - flags |= MGMT_ADV_FLAG_APPEARANCE; - break; - case 'n': - flags |= MGMT_ADV_FLAG_LOCAL_NAME; - break; - default: - advsize_usage(); - optind = 0; - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc != 1) { - advsize_usage(); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - instance = strtol(argv[0], NULL, 0); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - - cp.instance = instance; - cp.flags = cpu_to_le32(flags); - - if (!mgmt_send(mgmt, MGMT_OP_GET_ADV_SIZE_INFO, index, sizeof(cp), &cp, - adv_size_info_rsp, NULL, NULL)) { - error("Unable to send advertising size info command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void add_adv_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_add_advertising *rp = param; - - if (status != 0) { - error("Add Advertising failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Invalid Add Advertising response length (%u)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Instance added: %u", rp->instance); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void add_adv_usage(void) -{ - bt_shell_usage(); - print("Options:\n" - "\t -u, --uuid Service UUID\n" - "\t -d, --adv-data Advertising Data bytes\n" - "\t -s, --scan-rsp Scan Response Data bytes\n" - "\t -t, --timeout Timeout in seconds\n" - "\t -D, --duration Duration in seconds\n" - "\t -P, --phy Phy type, Specify 1M/2M/CODED\n" - "\t -c, --connectable \"connectable\" flag\n" - "\t -g, --general-discov \"general-discoverable\" flag\n" - "\t -l, --limited-discov \"limited-discoverable\" flag\n" - "\t -n, --scan-rsp-local-name \"local-name\" flag\n" - "\t -a, --scan-rsp-appearance \"appearance\" flag\n" - "\t -m, --managed-flags \"managed-flags\" flag\n" - "\t -p, --tx-power \"tx-power\" flag\n" - "e.g.:\n" - "\tadd-adv -u 180d -u 180f -d 080954657374204C45 1"); -} - -static struct option add_adv_options[] = { - { "help", 0, 0, 'h' }, - { "uuid", 1, 0, 'u' }, - { "adv-data", 1, 0, 'd' }, - { "scan-rsp", 1, 0, 's' }, - { "timeout", 1, 0, 't' }, - { "duration", 1, 0, 'D' }, - { "phy", 1, 0, 'P' }, - { "connectable", 0, 0, 'c' }, - { "general-discov", 0, 0, 'g' }, - { "limited-discov", 0, 0, 'l' }, - { "managed-flags", 0, 0, 'm' }, - { "tx-power", 0, 0, 'p' }, - { 0, 0, 0, 0} -}; - -static bool parse_bytes(char *optarg, uint8_t **bytes, size_t *len) -{ - unsigned i; - - if (!optarg) { - add_adv_usage(); - return false; - } - - *len = strlen(optarg); - - if (*len % 2) { - error("Malformed data"); - return false; - } - - *len /= 2; - if (*len > UINT8_MAX) { - error("Data too long"); - return false; - } - - *bytes = malloc(*len); - if (!*bytes) { - error("Failed to allocate memory"); - return false; - } - - for (i = 0; i < *len; i++) { - if (sscanf(optarg + (i * 2), "%2hhx", *bytes + i) != 1) { - error("Invalid data"); - free(*bytes); - *bytes = NULL; - return false; - } - } - - return true; -} - -#define MAX_AD_UUID_BYTES 32 - -static void cmd_add_adv(int argc, char **argv) -{ - struct mgmt_cp_add_advertising *cp = NULL; - int opt; - uint8_t *adv_data = NULL, *scan_rsp = NULL; - size_t adv_len = 0, scan_rsp_len = 0; - size_t cp_len; - uint8_t uuids[MAX_AD_UUID_BYTES]; - size_t uuid_bytes = 0; - uint8_t uuid_type = 0; - uint16_t timeout = 0, duration = 0; - uint8_t instance; - uuid_t uuid; - bool success = false; - bool quit = true; - uint32_t flags = 0; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+u:d:s:t:D:P:cglmphna", - add_adv_options, NULL)) != -1) { - switch (opt) { - case 'u': - if (bt_string2uuid(&uuid, optarg) < 0) { - print("Invalid UUID: %s", optarg); - goto done; - } - - if (uuid_type && uuid_type != uuid.type) { - print("UUID types must be consistent"); - goto done; - } - - if (uuid.type == SDP_UUID16) { - if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) { - print("Too many UUIDs"); - goto done; - } - - put_le16(uuid.value.uuid16, uuids + uuid_bytes); - uuid_bytes += 2; - } else if (uuid.type == SDP_UUID128) { - if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) { - print("Too many UUIDs"); - goto done; - } - - bswap_128(uuid.value.uuid128.data, - uuids + uuid_bytes); - uuid_bytes += 16; - } else { - printf("Unsupported UUID type"); - goto done; - } - - if (!uuid_type) - uuid_type = uuid.type; - - break; - case 'd': - if (adv_len) { - print("Only one adv-data option allowed"); - goto done; - } - - if (!parse_bytes(optarg, &adv_data, &adv_len)) - goto done; - break; - case 's': - if (scan_rsp_len) { - print("Only one scan-rsp option allowed"); - goto done; - } - - if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len)) - goto done; - break; - case 't': - timeout = strtol(optarg, NULL, 0); - break; - case 'D': - duration = strtol(optarg, NULL, 0); - break; - case 'c': - flags |= MGMT_ADV_FLAG_CONNECTABLE; - break; - case 'g': - flags |= MGMT_ADV_FLAG_DISCOV; - break; - case 'l': - flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; - break; - case 'm': - flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; - break; - case 'p': - flags |= MGMT_ADV_FLAG_TX_POWER; - break; - case 'n': - flags |= MGMT_ADV_FLAG_LOCAL_NAME; - break; - case 'a': - flags |= MGMT_ADV_FLAG_APPEARANCE; - break; - case 'P': - if (strcasecmp(optarg, "1M") == 0) - flags |= MGMT_ADV_FLAG_SEC_1M; - else if (strcasecmp(optarg, "2M") == 0) - flags |= MGMT_ADV_FLAG_SEC_2M; - else if (strcasecmp(optarg, "CODED") == 0) - flags |= MGMT_ADV_FLAG_SEC_CODED; - else - goto done; - break; - case 'h': - success = true; - /* fall through */ - default: - add_adv_usage(); - optind = 0; - goto done; - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc != 1) { - add_adv_usage(); - goto done; - } - - if (uuid_bytes) - uuid_bytes += 2; - - instance = strtol(argv[0], NULL, 0); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len; - cp = malloc0(cp_len); - if (!cp) - goto done; - - cp->instance = instance; - put_le32(flags, &cp->flags); - put_le16(timeout, &cp->timeout); - put_le16(duration, &cp->duration); - cp->adv_data_len = adv_len + uuid_bytes; - cp->scan_rsp_len = scan_rsp_len; - - if (uuid_bytes) { - cp->data[0] = uuid_bytes - 1; - cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07; - memcpy(cp->data + 2, uuids, uuid_bytes - 2); - } - - if (adv_len) - memcpy(cp->data + uuid_bytes, adv_data, adv_len); - - if (scan_rsp_len) - memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len); - - if (!mgmt_send(mgmt, MGMT_OP_ADD_ADVERTISING, index, cp_len, cp, - add_adv_rsp, NULL, NULL)) { - error("Unable to send \"Add Advertising\" command"); - goto done; - } - - quit = false; - -done: - free(adv_data); - free(scan_rsp); - free(cp); - - if (quit) - bt_shell_noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); -} - -static void rm_adv_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_remove_advertising *rp = param; - - if (status != 0) { - error("Remove Advertising failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Invalid Remove Advertising response length (%u)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Instance removed: %u", rp->instance); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_rm_adv(int argc, char **argv) -{ - struct mgmt_cp_remove_advertising cp; - uint8_t instance; - uint16_t index; - - instance = strtol(argv[1], NULL, 0); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - memset(&cp, 0, sizeof(cp)); - - cp.instance = instance; - - if (!mgmt_send(mgmt, MGMT_OP_REMOVE_ADVERTISING, index, sizeof(cp), &cp, - rm_adv_rsp, NULL, NULL)) { - error("Unable to send \"Remove Advertising\" command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_clr_adv(int argc, char **argv) -{ - char *all_instances = "0"; - char *rm_argv[] = { "rm-adv", all_instances, NULL }; - - cmd_rm_adv(2, rm_argv); -} - -static void add_ext_adv_params_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_rp_add_ext_adv_params *rp = param; - - if (status != 0) { - error("Add Ext Adv Params failed status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Invalid Add Ext Adv Params response length (%u)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Instance added: %u", rp->instance); - print("Tx Power: %u", rp->tx_power); - print("Max adv data len: %u", rp->max_adv_data_len); - print("Max scan resp len: %u", rp->max_scan_rsp_len); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void add_ext_adv_params_usage(void) -{ - bt_shell_usage(); - print("Options:\n" - "\t -d, --duration Duration in seconds\n" - "\t -t, --timeout Timeout in seconds\n" - "\t -r, --min-interval Minimum interval\n" - "\t -x, --max-interval Maximum interval\n" - "\t -w, --tx-power Tx power\n" - "\t -P, --phy Phy type, Specify 1M/2M/CODED\n" - "\t -c, --connectable \"connectable\" flag\n" - "\t -g, --general-discov \"general-discoverable\" flag\n" - "\t -l, --limited-discov \"limited-discoverable\" flag\n" - "\t -m, --managed-flags \"managed-flags\" flag\n" - "\t -p, --add-tx-power \"tx-power\" flag\n" - "\t -a, --scan-rsp-appearance \"appearance\" flag\n" - "\t -n, --scan-rsp-local-name \"local-name\" flag\n" - "\t -s, --adv-scan-rsp \"scan resp in adv\" flag\n" - "\t -h, --help Show help\n" - "e.g.:\n" - "\tadd-ext-adv-params -r 0x801 -x 0x802 -P 2M -g 1"); -} - -static struct option add_ext_adv_params_options[] = { - { "help", 0, 0, 'h' }, - { "duration", 1, 0, 'd' }, - { "timeout", 1, 0, 't' }, - { "min-internal", 1, 0, 'r' }, - { "max-interval", 1, 0, 'x' }, - { "tx-power", 1, 0, 'w' }, - { "phy", 1, 0, 'P' }, - { "connectable", 0, 0, 'c' }, - { "general-discov", 0, 0, 'g' }, - { "limited-discov", 0, 0, 'l' }, - { "scan-rsp-local-name", 0, 0, 'n' }, - { "scan-rsp-appearance", 0, 0, 'a' }, - { "managed-flags", 0, 0, 'm' }, - { "add-tx-power", 0, 0, 'p' }, - { "adv-scan-rsp", 0, 0, 's' }, - { 0, 0, 0, 0} -}; - -static void cmd_add_ext_adv_params(int argc, char **argv) -{ - struct mgmt_cp_add_ext_adv_params *cp = NULL; - int opt; - uint16_t timeout = 0, duration = 0; - uint8_t instance; - bool success = false; - bool quit = true; - uint32_t flags = 0; - uint32_t min_interval = 0; - uint32_t max_interval = 0; - uint8_t tx_power = 0; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "d:t:r:x:w:P:cglmpansh", - add_ext_adv_params_options, NULL)) != -1) { - switch (opt) { - case 'd': - duration = strtol(optarg, NULL, 0); - flags |= MGMT_ADV_PARAM_DURATION; - break; - case 't': - timeout = strtol(optarg, NULL, 0); - flags |= MGMT_ADV_PARAM_TIMEOUT; - break; - case 'r': - min_interval = strtol(optarg, NULL, 0); - break; - case 'x': - max_interval = strtol(optarg, NULL, 0); - break; - case 'w': - tx_power = strtol(optarg, NULL, 0); - flags |= MGMT_ADV_PARAM_TX_POWER; - break; - case 'P': - if (strcasecmp(optarg, "1M") == 0) - flags |= MGMT_ADV_FLAG_SEC_1M; - else if (strcasecmp(optarg, "2M") == 0) - flags |= MGMT_ADV_FLAG_SEC_2M; - else if (strcasecmp(optarg, "CODED") == 0) - flags |= MGMT_ADV_FLAG_SEC_CODED; - else - goto done; - break; - case 'c': - flags |= MGMT_ADV_FLAG_CONNECTABLE; - break; - case 'g': - flags |= MGMT_ADV_FLAG_DISCOV; - break; - case 'l': - flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; - break; - case 'n': - flags |= MGMT_ADV_FLAG_LOCAL_NAME; - break; - case 'a': - flags |= MGMT_ADV_FLAG_APPEARANCE; - break; - case 'm': - flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; - break; - case 'p': - flags |= MGMT_ADV_FLAG_TX_POWER; - break; - case 's': - flags |= MGMT_ADV_PARAM_SCAN_RSP; - break; - case 'h': - success = true; - /* fall through */ - default: - add_ext_adv_params_usage(); - optind = 0; - goto done; - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc != 1) { - add_ext_adv_params_usage(); - goto done; - } - - /* Only if both min_interval and max_interval are defined */ - if (min_interval && max_interval) - flags |= MGMT_ADV_PARAM_INTERVALS; - - instance = strtol(argv[0], NULL, 0); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp = malloc0(sizeof(*cp)); - if (!cp) - goto done; - - cp->instance = instance; - put_le32(flags, &cp->flags); - put_le16(timeout, &cp->timeout); - put_le16(duration, &cp->duration); - put_le32(min_interval, &cp->min_interval); - put_le32(max_interval, &cp->max_interval); - cp->tx_power = tx_power; - - if (!mgmt_send(mgmt, MGMT_OP_ADD_EXT_ADV_PARAMS, index, sizeof(*cp), cp, - add_ext_adv_params_rsp, NULL, NULL)) { - error("Unable to send \"Add Ext Advertising Params\" command"); - goto done; - } - - quit = false; - -done: - free(cp); - - if (quit) - bt_shell_noninteractive_quit(success ? - EXIT_SUCCESS : EXIT_FAILURE); -} - -static void add_ext_adv_data_rsp(uint8_t status, uint16_t len, - const void *param, void *user_data) -{ - const struct mgmt_rp_add_ext_adv_data *rp = param; - - if (status != 0) { - error("Add Ext Advertising Data failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len != sizeof(*rp)) { - error("Invalid Add Ext Advertising Data response length (%u)", - len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Instance added: %u", rp->instance); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void add_ext_adv_data_usage(void) -{ - bt_shell_usage(); - print("Options:\n" - "\t -u, --uuid Service UUID\n" - "\t -d, --adv-data Advertising Data bytes\n" - "\t -s, --scan-rsp Scan Response Data bytes\n" - "e.g.:\n" - "\tadd-ext-adv-data -u 180d -u 180f -d 080954657374204C45 1"); -} - -static struct option add_ext_adv_data_options[] = { - { "help", 0, 0, 'h' }, - { "uuid", 1, 0, 'u' }, - { "adv-data", 1, 0, 'd' }, - { "scan-rsp", 1, 0, 's' }, - { 0, 0, 0, 0} -}; - -static void cmd_add_ext_adv_data(int argc, char **argv) -{ - struct mgmt_cp_add_ext_adv_data *cp = NULL; - int opt; - uint8_t *adv_data = NULL, *scan_rsp = NULL; - size_t adv_len = 0, scan_rsp_len = 0; - size_t cp_len; - uint8_t uuids[MAX_AD_UUID_BYTES]; - size_t uuid_bytes = 0; - uint8_t uuid_type = 0; - uint8_t instance; - uuid_t uuid; - bool success = false; - bool quit = true; - uint16_t index; - - while ((opt = getopt_long(argc, argv, "+u:d:s:h", - add_ext_adv_data_options, NULL)) != -1) { - switch (opt) { - case 'u': - if (bt_string2uuid(&uuid, optarg) < 0) { - print("Invalid UUID: %s", optarg); - goto done; - } - - if (uuid_type && uuid_type != uuid.type) { - print("UUID types must be consistent"); - goto done; - } - - if (uuid.type == SDP_UUID16) { - if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) { - print("Too many UUIDs"); - goto done; - } - - put_le16(uuid.value.uuid16, uuids + uuid_bytes); - uuid_bytes += 2; - } else if (uuid.type == SDP_UUID128) { - if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) { - print("Too many UUIDs"); - goto done; - } - - bswap_128(uuid.value.uuid128.data, - uuids + uuid_bytes); - uuid_bytes += 16; - } else { - printf("Unsupported UUID type"); - goto done; - } - - if (!uuid_type) - uuid_type = uuid.type; - - break; - case 'd': - if (adv_len) { - print("Only one adv-data option allowed"); - goto done; - } - - if (!parse_bytes(optarg, &adv_data, &adv_len)) - goto done; - break; - case 's': - if (scan_rsp_len) { - print("Only one scan-rsp option allowed"); - goto done; - } - - if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len)) - goto done; - break; - case 'h': - success = true; - /* fall through */ - default: - add_ext_adv_data_usage(); - optind = 0; - goto done; - } - } - - argc -= optind; - argv += optind; - optind = 0; - - if (argc != 1) { - add_ext_adv_data_usage(); - goto done; - } - - if (uuid_bytes) - uuid_bytes += 2; - - instance = strtol(argv[0], NULL, 0); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len; - cp = malloc0(cp_len); - if (!cp) - goto done; - - cp->instance = instance; - cp->adv_data_len = adv_len + uuid_bytes; - cp->scan_rsp_len = scan_rsp_len; - - if (uuid_bytes) { - cp->data[0] = uuid_bytes - 1; - cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07; - memcpy(cp->data + 2, uuids, uuid_bytes - 2); - } - - if (adv_len) - memcpy(cp->data + uuid_bytes, adv_data, adv_len); - - if (scan_rsp_len) - memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len); - - if (!mgmt_send(mgmt, MGMT_OP_ADD_EXT_ADV_DATA, index, cp_len, cp, - add_ext_adv_data_rsp, NULL, NULL)) { - error("Unable to send \"Add Ext Advertising Data\" command"); - goto done; - } - - quit = false; - -done: - free(adv_data); - free(scan_rsp); - free(cp); - - if (quit) - bt_shell_noninteractive_quit(success ? - EXIT_SUCCESS : EXIT_FAILURE); -} - -static void appearance_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) - error("Could not set Appearance with status 0x%02x (%s)", - status, mgmt_errstr(status)); - else - print("Appearance successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_appearance(int argc, char **argv) -{ - struct mgmt_cp_set_appearance cp; - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - cp.appearance = cpu_to_le16(strtol(argv[1], NULL, 0)); - - if (mgmt_send(mgmt, MGMT_OP_SET_APPEARANCE, index, sizeof(cp), &cp, - appearance_rsp, NULL, NULL) == 0) { - error("Unable to send appearance cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static const char *phys_str[] = { - "BR1M1SLOT", - "BR1M3SLOT", - "BR1M5SLOT", - "EDR2M1SLOT", - "EDR2M3SLOT", - "EDR2M5SLOT", - "EDR3M1SLOT", - "EDR3M3SLOT", - "EDR3M5SLOT", - "LE1MTX", - "LE1MRX", - "LE2MTX", - "LE2MRX", - "LECODEDTX", - "LECODEDRX", -}; - -static const char *phys2str(uint32_t phys) -{ - static char str[256]; - unsigned int i; - int off; - - off = 0; - str[0] = '\0'; - - for (i = 0; i < NELEM(phys_str); i++) { - if ((phys & (1 << i)) != 0) - off += snprintf(str + off, sizeof(str) - off, "%s ", - phys_str[i]); - } - - return str; -} - -static bool str2phy(const char *phy_str, uint32_t *phy_val) -{ - unsigned int i; - - for (i = 0; i < NELEM(phys_str); i++) { - if (strcasecmp(phys_str[i], phy_str) == 0) { - *phy_val = (1 << i); - return true; - } - } - - return false; -} - -static void get_phy_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_get_phy_confguration *rp = param; - uint32_t supported_phys, selected_phys, configurable_phys; - - if (status != 0) { - error("Get PHY Configuration failed with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small get-phy reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - supported_phys = get_le32(&rp->supported_phys); - configurable_phys = get_le32(&rp->configurable_phys); - selected_phys = get_le32(&rp->selected_phys); - - print("Supported phys: %s", phys2str(supported_phys)); - print("Configurable phys: %s", phys2str(configurable_phys)); - print("Selected phys: %s", phys2str(selected_phys)); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void get_phy(void) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (mgmt_send(mgmt, MGMT_OP_GET_PHY_CONFIGURATION, index, 0, NULL, - get_phy_rsp, NULL, NULL) == 0) { - error("Unable to send Get PHY cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void set_phy_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - if (status != 0) { - error("Could not set PHY Configuration with status 0x%02x (%s)", - status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("PHY Configuration successfully set"); - - bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_phy(int argc, char **argv) -{ - struct mgmt_cp_set_phy_confguration cp; - int i; - uint32_t phys = 0; - uint16_t index; - - if (argc < 2) - return get_phy(); - - for (i = 1; i < argc; i++) { - uint32_t phy_val; - - if (str2phy(argv[i], &phy_val)) - phys |= phy_val; - } - - cp.selected_phys = cpu_to_le32(phys); - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (mgmt_send(mgmt, MGMT_OP_SET_PHY_CONFIGURATION, index, sizeof(cp), - &cp, set_phy_rsp, NULL, NULL) == 0) { - error("Unable to send %s cmd", - mgmt_opstr(MGMT_OP_SET_PHY_CONFIGURATION)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void cmd_wbs(int argc, char **argv) -{ - cmd_setting(MGMT_OP_SET_WIDEBAND_SPEECH, argc, argv); -} - -static const char * const advmon_features_str[] = { - "Pattern monitor with logic OR.", -}; - -static const char *advmon_features2str(uint32_t features) -{ - static char str[512]; - unsigned int off, i; - - off = 0; - snprintf(str, sizeof(str), "\n\tNone"); - - for (i = 0; i < NELEM(advmon_features_str); i++) { - if ((features & (1 << i)) != 0 && off < sizeof(str)) - off += snprintf(str + off, sizeof(str) - off, "\n\t%s", - advmon_features_str[i]); - } - - return str; -} - -static void advmon_features_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_read_adv_monitor_features *rp = param; - uint32_t supported_features, enabled_features; - uint16_t num_handles; - int i; - - if (status != MGMT_STATUS_SUCCESS) { - error("Reading adv monitor features failed with status 0x%02x " - "(%s)", status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - if (len < sizeof(*rp)) { - error("Too small adv monitor features reply (%u bytes)", len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - supported_features = le32_to_cpu(rp->supported_features); - enabled_features = le32_to_cpu(rp->enabled_features); - num_handles = le16_to_cpu(rp->num_handles); - - if (len < sizeof(*rp) + num_handles * sizeof(uint16_t)) { - error("Handles count (%u) doesn't match reply length (%u)", - num_handles, len); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Supported features:%s", advmon_features2str(supported_features)); - print("Enabled features:%s", advmon_features2str(enabled_features)); - print("Max number of handles: %u", le16_to_cpu(rp->max_num_handles)); - print("Max number of patterns: %u", rp->max_num_patterns); - print("Handles list with %u item%s", num_handles, - num_handles == 0 ? "" : num_handles == 1 ? ":" : "s:"); - for (i = 0; i < num_handles; i++) - print("\t0x%04x ", le16_to_cpu(rp->handles[i])); - - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_advmon_features(int argc, char **argv) -{ - uint16_t index; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_READ_ADV_MONITOR_FEATURES, index, 0, NULL, - advmon_features_rsp, NULL, NULL)) { - error("Unable to send advertising monitor features command"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void advmon_add_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_add_adv_patterns_monitor *rp = param; - - if (status != MGMT_STATUS_SUCCESS) { - error("Could not add advertisement monitor with status " - "0x%02x (%s)", status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Advertisement monitor with handle:0x%04x added", - le16_to_cpu(rp->monitor_handle)); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static bool str2pattern(struct mgmt_adv_pattern *pattern, const char *str) -{ - int type_len, offset_len, offset_end_pos, str_len; - int i, j; - char pattern_str[62] = { 0 }; - char tmp; - - if (sscanf(str, "%2hhx%n:%2hhx%n:%61s", &pattern->ad_type, &type_len, - &pattern->offset, &offset_end_pos, pattern_str) != 3) - return false; - - offset_len = offset_end_pos - type_len - 1; - str_len = strlen(pattern_str); - pattern->length = str_len / 2 + str_len % 2; - - if (type_len > 2 || offset_len > 2 || - pattern->offset + pattern->length > 31) - return false; - - for (i = 0, j = 0; i < str_len; i++, j++) { - if (sscanf(&pattern_str[i++], "%2hhx", &pattern->value[j]) - != 1) - return false; - if (i < str_len && sscanf(&pattern_str[i], "%1hhx", &tmp) != 1) - return false; - } - - return true; -} - -static struct option add_monitor_rssi_options[] = { - { "help", 0, 0, 'h' }, - { "high-threshold", 1, 0, 'R' }, - { "low-threshold", 1, 0, 'r' }, - { "high-timeout", 1, 0, 'T' }, - { "low-timeout", 1, 0, 't' }, - { "sampling", 1, 0, 's' }, - { 0, 0, 0, 0 } -}; - -static void advmon_add_pattern_usage(void) -{ - bt_shell_usage(); - print("patterns format:\n" - "\t [patterns]\n" - "e.g.:\n" - "\tadd-pattern 0:1:c504 ff:a:9a55beef"); -} - -static void advmon_add_pattern_rssi_usage(void) -{ - bt_shell_usage(); - print("RSSI options:\n" - "\t -R, --high-threshold " - "RSSI high threshold. Default: -70\n" - "\t -r, --low-threshold " - "RSSI low threshold. Default: -50\n" - "\t -T, --high-timeout " - "RSSI high threshold duration. Default: 0\n" - "\t -t, --low-timeout " - "RSSI low threshold duration. Default: 5\n" - "\t -s, --sampling " - "RSSI sampling period. Default: 0\n" - "patterns format:\n" - "\t [patterns]\n" - "e.g.:\n" - "\tadd-pattern-rssi -R 0xb2 -r -102 0:1:c504 ff:a:9a55beef"); -} - -static void cmd_advmon_add_pattern(int argc, char **argv) -{ - bool success = true; - uint16_t index; - int i, cp_len; - struct mgmt_cp_add_adv_monitor *cp = NULL; - - if (!strcmp(argv[1], "-h")) - goto done; - - argc -= 1; - argv += 1; - - cp_len = sizeof(*cp) + argc * sizeof(struct mgmt_adv_pattern); - cp = malloc0(cp_len); - if (!cp) { - error("Failed to alloc patterns."); - success = false; - goto done; - } - - cp->pattern_count = argc; - - for (i = 0; i < argc; i++) { - if (!str2pattern(&cp->patterns[i], argv[i])) { - error("Failed to parse monitor patterns."); - success = false; - goto done; - } - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_ADD_ADV_PATTERNS_MONITOR, index, - cp_len, cp, advmon_add_rsp, NULL, NULL)) { - error("Unable to send Add Advertising Monitor command"); - success = false; - goto done; - } - - free(cp); - return; - -done: - free(cp); - advmon_add_pattern_usage(); - bt_shell_noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); -} - -static void cmd_advmon_add_pattern_rssi(int argc, char **argv) -{ - bool success = true; - int opt; - int8_t rssi_low = -70; - int8_t rssi_high = -50; - uint16_t rssi_low_timeout = 5; - uint16_t rssi_high_timeout = 0; - uint8_t rssi_sampling_period = 0; - uint16_t index; - int i, cp_len; - struct mgmt_cp_add_adv_patterns_monitor_rssi *cp = NULL; - - while ((opt = getopt_long(argc, argv, "+hr:R:t:T:s:", - add_monitor_rssi_options, NULL)) != -1) { - switch (opt) { - case 'h': - goto done; - case 'r': - rssi_low = strtol(optarg, NULL, 0); - break; - case 'R': - rssi_high = strtol(optarg, NULL, 0); - break; - case 't': - rssi_low_timeout = strtol(optarg, NULL, 0); - break; - case 'T': - rssi_high_timeout = strtol(optarg, NULL, 0); - break; - case 's': - rssi_sampling_period = strtol(optarg, NULL, 0); - break; - default: - success = false; - goto done; - } - } - - argc -= optind; - argv += optind; - optind = 0; - - cp_len = sizeof(*cp) + argc * sizeof(struct mgmt_adv_pattern); - cp = malloc0(cp_len); - if (!cp) { - error("Failed to alloc patterns."); - success = false; - goto done; - } - - cp->pattern_count = argc; - cp->rssi.high_threshold = rssi_high; - cp->rssi.low_threshold = rssi_low; - cp->rssi.high_threshold_timeout = htobs(rssi_high_timeout); - cp->rssi.low_threshold_timeout = htobs(rssi_low_timeout); - cp->rssi.sampling_period = rssi_sampling_period; - - for (i = 0; i < argc; i++) { - if (!str2pattern(&cp->patterns[i], argv[i])) { - error("Failed to parse monitor patterns."); - success = false; - goto done; - } - } - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (!mgmt_send(mgmt, MGMT_OP_ADD_ADV_PATTERNS_MONITOR_RSSI, index, - cp_len, cp, advmon_add_rsp, NULL, NULL)) { - error("Unable to send Add Advertising Monitor RSSI command"); - success = false; - goto done; - } - - free(cp); - return; - -done: - free(cp); - optind = 0; - advmon_add_pattern_rssi_usage(); - bt_shell_noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE); -} - -static void advmon_remove_rsp(uint8_t status, uint16_t len, const void *param, - void *user_data) -{ - const struct mgmt_rp_remove_adv_monitor *rp = param; - - if (status != MGMT_STATUS_SUCCESS) { - error("Could not remove advertisement monitor with status " - "0x%02x (%s)", status, mgmt_errstr(status)); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - print("Advertisement monitor with handle: 0x%04x removed", - le16_to_cpu(rp->monitor_handle)); - return bt_shell_noninteractive_quit(EXIT_SUCCESS); -} - -static void cmd_advmon_remove(int argc, char **argv) -{ - struct mgmt_cp_remove_adv_monitor cp; - uint16_t index, monitor_handle; - - index = mgmt_index; - if (index == MGMT_INDEX_NONE) - index = 0; - - if (sscanf(argv[1], "%hx", &monitor_handle) != 1) { - error("Wrong formatted handle argument"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } - - cp.monitor_handle = cpu_to_le16(monitor_handle); - if (mgmt_send(mgmt, MGMT_OP_REMOVE_ADV_MONITOR, index, sizeof(cp), &cp, - advmon_remove_rsp, NULL, NULL) == 0) { - error("Unable to send appearance cmd"); - return bt_shell_noninteractive_quit(EXIT_FAILURE); - } -} - -static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index) -{ - mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED, index, - class_of_dev_changed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index, - local_name_changed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found, - mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin, - mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm, - mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index, - request_passkey, mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index, - passkey_notify, mgmt, NULL); - mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index, - unconf_index_added, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index, - unconf_index_removed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index, - new_config_options, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_EXT_INDEX_ADDED, index, - ext_index_added, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_EXT_INDEX_REMOVED, index, - ext_index_removed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_LOCAL_OOB_DATA_UPDATED, index, - local_oob_data_updated, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_ADVERTISING_ADDED, index, - advertising_added, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_ADVERTISING_REMOVED, index, - advertising_removed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_DEVICE_FLAGS_CHANGED, index, - flags_changed, NULL, NULL); - mgmt_register(mgmt, MGMT_EV_ADV_MONITOR_ADDED, index, advmon_added, - NULL, NULL); - mgmt_register(mgmt, MGMT_EV_ADV_MONITOR_REMOVED, index, advmon_removed, - NULL, NULL); -} - -static void cmd_select(int argc, char **argv) -{ - mgmt_cancel_all(mgmt); - mgmt_unregister_all(mgmt); - - set_index(argv[1]); - - register_mgmt_callbacks(mgmt, mgmt_index); - - print("Selected index %u", mgmt_index); - - update_prompt(mgmt_index); -} - -static const struct bt_shell_menu monitor_menu = { - .name = "monitor", - .desc = "Advertisement Monitor Submenu", - .entries = { - { "features", NULL, - cmd_advmon_features, "Show advertisement monitor " - "features" }, - { "remove", "", - cmd_advmon_remove, "Remove advertisement monitor " }, - { "add-pattern", "[-h] ", - cmd_advmon_add_pattern, "Add advertisement monitor pattern" }, - { "add-pattern-rssi", "[options] ", - cmd_advmon_add_pattern_rssi, - "Add advertisement monitor pattern with RSSI options" }, - { } }, -}; - -static const struct bt_shell_menu main_menu = { - .name = "main", - .entries = { - { "select", "", - cmd_select, "Select a different index" }, - { "revision", NULL, - cmd_revision, "Get the MGMT Revision" }, - { "commands", NULL, - cmd_commands, "List supported commands" }, - { "config", NULL, - cmd_config, "Show configuration info" }, - { "info", NULL, - cmd_info, "Show controller info" }, - { "extinfo", NULL, - cmd_extinfo, "Show extended controller info" }, - { "auto-power", NULL, - cmd_auto_power, "Power all available features" }, - { "power", "", - cmd_power, "Toggle powered state" }, - { "discov", " [timeout]", - cmd_discov, "Toggle discoverable state" }, - { "connectable", "", - cmd_connectable, "Toggle connectable state" }, - { "fast-conn", "", - cmd_fast_conn, "Toggle fast connectable state" }, - { "bondable", "", - cmd_bondable, "Toggle bondable state" }, - { "pairable", "", - cmd_bondable, "Toggle bondable state" }, - { "linksec", "", - cmd_linksec, "Toggle link level security" }, - { "ssp", "", - cmd_ssp, "Toggle SSP mode" }, - { "sc", "", - cmd_sc, "Toogle SC support" }, - { "hs", "", - cmd_hs, "Toggle HS support" }, - { "le", "", - cmd_le, "Toggle LE support" }, - { "advertising", "", - cmd_advertising, "Toggle LE advertising", }, - { "bredr", "", - cmd_bredr, "Toggle BR/EDR support", }, - { "privacy", " [irk]", - cmd_privacy, "Toggle privacy support" }, - { "class", " ", - cmd_class, "Set device major/minor class" }, - { "disconnect", "[-t type] ", - cmd_disconnect, "Disconnect device" }, - { "con", NULL, - cmd_con, "List connections" }, - { "find", "[-l|-b] [-L]", - cmd_find, "Discover nearby devices" }, - { "find-service", "[-u UUID] [-r RSSI_Threshold] [-l|-b]", - cmd_find_service, "Discover nearby service" }, - { "stop-find", "[-l|-b]", - cmd_stop_find, "Stop discovery" }, - { "name", " [shortname]", - cmd_name, "Set local name" }, - { "pair", "[-c cap] [-t type] ", - cmd_pair, "Pair with a remote device" }, - { "cancelpair", "[-t type] ", - cmd_cancel_pair, "Cancel pairing" }, - { "unpair", "[-t type] ", - cmd_unpair, "Unpair device" }, - { "keys", NULL, - cmd_keys, "Load Link Keys" }, - { "ltks", NULL, - cmd_ltks, "Load Long Term Keys" }, - { "irks", "[--local index] [--file file path]", - cmd_irks, "Load Identity Resolving Keys" }, - { "block", "[-t type] ", - cmd_block, "Block Device" }, - { "unblock", "[-t type] ", - cmd_unblock, "Unblock Device" }, - { "add-uuid", " ", - cmd_add_uuid, "Add UUID" }, - { "rm-uuid", "", - cmd_remove_uuid, "Remove UUID" }, - { "clr-uuids", NULL, - cmd_clr_uuids, "Clear UUIDs" }, - { "local-oob", NULL, - cmd_local_oob, "Local OOB data" }, - { "remote-oob", "[-t ] [-r ] " - "[-h ] [-R ] " - "[-H ] ", - cmd_remote_oob, "Remote OOB data" }, - { "did", ":::", - cmd_did, "Set Device ID" }, - { "static-addr", "
", - cmd_static_addr, "Set static address" }, - { "public-addr", "
", - cmd_public_addr, "Set public address" }, - { "ext-config", "", - cmd_ext_config, "External configuration" }, - { "debug-keys", "", - cmd_debug_keys, "Toogle debug keys" }, - { "conn-info", "[-t type] ", - cmd_conn_info, "Get connection information" }, - { "io-cap", "", - cmd_io_cap, "Set IO Capability" }, - { "scan-params", " ", - cmd_scan_params, "Set Scan Parameters" }, - { "get-clock", "[address]", - cmd_clock_info, "Get Clock Information" }, - { "add-device", "[-a action] [-t type]
", - cmd_add_device, "Add Device" }, - { "del-device", "[-t type]
", - cmd_del_device, "Remove Device" }, - { "clr-devices", NULL, - cmd_clr_devices, "Clear Devices" }, - { "bredr-oob", NULL, - cmd_bredr_oob, "Local OOB data (BR/EDR)" }, - { "le-oob", NULL, - cmd_le_oob, "Local OOB data (LE)" }, - { "advinfo", NULL, - cmd_advinfo, "Show advertising features" }, - { "advsize", "[options] ", - cmd_advsize, "Show advertising size info" }, - { "add-adv", "[options] ", - cmd_add_adv, "Add advertising instance" }, - { "rm-adv", "", - cmd_rm_adv, "Remove advertising instance" }, - { "clr-adv", NULL, - cmd_clr_adv, "Clear advertising instances" }, - { "add-ext-adv-params", "[options] ", - cmd_add_ext_adv_params, - "Add extended advertising params" }, - { "add-ext-adv-data", "[options] ", - cmd_add_ext_adv_data, - "Add extended advertising data" }, - { "appearance", "", - cmd_appearance, "Set appearance" }, - { "phy", "[LE1MTX] [LE1MRX] [LE2MTX] [LE2MRX] " - "[LECODEDTX] [LECODEDRX] " - "[BR1M1SLOT] [BR1M3SLOT] [BR1M5SLOT]" - "[EDR2M1SLOT] [EDR2M3SLOT] [EDR2M5SLOT]" - "[EDR3M1SLOT] [EDR3M3SLOT] [EDR3M5SLOT]", - cmd_phy, "Get/Set PHY Configuration" }, - { "wbs", "", - cmd_wbs, "Toggle Wideband-Speech support"}, - { "secinfo", NULL, - cmd_secinfo, "Show security information" }, - { "expinfo", NULL, - cmd_expinfo, "Show experimental features" }, - { "exp-debug", "", - cmd_exp_debug, "Set debug feature" }, - { "exp-privacy", "", - cmd_exp_privacy, "Set LL privacy feature" }, - { "exp-quality", "", cmd_exp_quality, - "Set bluetooth quality report feature" }, - { "exp-offload", "", - cmd_exp_offload_codecs, "Toggle codec support" }, - { "read-sysconfig", NULL, - cmd_read_sysconfig, "Read System Configuration" }, - { "set-sysconfig", "<-v|-h> [options...]", - cmd_set_sysconfig, "Set System Configuration" }, - { "get-flags", "[-t type]
", - cmd_get_flags, "Get device flags" }, - { "set-flags", "[-f flags] [-t type]
", - cmd_set_flags, "Set device flags" }, - {} }, -}; - -static void mgmt_debug(const char *str, void *user_data) -{ - const char *prefix = user_data; - - print("%s%s", prefix, str); -} +#include "client/mgmt.h" static const char *index_option; @@ -6062,30 +45,17 @@ int main(int argc, char *argv[]) int status; bt_shell_init(argc, argv, &opt); - bt_shell_set_menu(&main_menu); - bt_shell_add_submenu(&monitor_menu); - mgmt = mgmt_new_default(); - if (!mgmt) { + if (!mgmt_add_submenu()) { fprintf(stderr, "Unable to open mgmt_socket\n"); return EXIT_FAILURE; } - if (getenv("MGMT_DEBUG")) - mgmt_set_debug(mgmt, mgmt_debug, "mgmt: ", NULL); - - if (index_option) - set_index(index_option); - - register_mgmt_callbacks(mgmt, mgmt_index); - bt_shell_attach(fileno(stdin)); - update_prompt(mgmt_index); + mgmt_set_index(index_option); status = bt_shell_run(); - mgmt_cancel_all(mgmt); - mgmt_unregister_all(mgmt); - mgmt_unref(mgmt); + mgmt_remove_submenu(); return status; }