2 * BlueZ - Bluetooth protocol stack for Linux
4 * Copyright (C) 2011 Intel Corporation. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
43 #include <readline/readline.h>
44 #include <readline/history.h>
46 #include "lib/bluetooth.h"
48 #include "lib/hci_lib.h"
50 #include "lib/sdp_lib.h"
52 #include "src/uuid-helper.h"
55 #include "client/display.h"
56 #include "src/shared/mainloop.h"
57 #include "src/shared/io.h"
58 #include "src/shared/util.h"
59 #include "src/shared/mgmt.h"
61 #define SCAN_TYPE_BREDR (1 << BDADDR_BREDR)
62 #define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM))
63 #define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE)
65 static struct mgmt *mgmt = NULL;
66 static uint16_t mgmt_index = MGMT_INDEX_NONE;
68 static bool discovery = false;
69 static bool resolve_names = true;
70 static bool interactive = false;
72 static char *saved_prompt = NULL;
73 static int saved_point = 0;
78 struct mgmt_addr_info addr;
80 .index = MGMT_INDEX_NONE,
83 static int pending_index = 0;
86 #define MIN(x, y) ((x) < (y) ? (x) : (y))
89 #define PROMPT_ON COLOR_BLUE "[mgmt]" COLOR_OFF "# "
91 static void update_prompt(uint16_t index)
95 if (index == MGMT_INDEX_NONE)
96 snprintf(str, sizeof(str), "%s# ",
97 COLOR_BLUE "[mgmt]" COLOR_OFF);
99 snprintf(str, sizeof(str),
100 COLOR_BLUE "[hci%u]" COLOR_OFF "# ", index);
104 saved_prompt = strdup(str);
111 static void noninteractive_quit(int status)
116 if (status == EXIT_SUCCESS)
117 mainloop_exit_success();
119 mainloop_exit_failure();
122 #define print(fmt, arg...) do { \
124 rl_printf(fmt "\n", ## arg); \
126 printf(fmt "\n", ## arg); \
129 #define error(fmt, arg...) do { \
131 rl_printf(COLOR_RED fmt "\n" COLOR_OFF, ## arg); \
133 fprintf(stderr, fmt "\n", ## arg); \
136 static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen)
140 len = MIN((strlen(hexstr) / 2), buflen);
143 for (i = 0; i < len; i++)
144 sscanf(hexstr + (i * 2), "%02hhX", &buf[i]);
149 static size_t bin2hex(const uint8_t *buf, size_t buflen, char *str,
154 for (i = 0; i < buflen && i < (strlen / 2); i++)
155 sprintf(str + (i * 2), "%02x", buf[i]);
160 static void print_eir(const uint8_t *eir, uint16_t eir_len)
165 while (parsed < eir_len - 1) {
166 uint8_t field_len = eir[0];
171 parsed += field_len + 1;
173 if (parsed > eir_len)
178 print("Flags: 0x%02x", eir[2]);
181 print("Class of Device: 0x%02x%02x%02x",
182 eir[4], eir[3], eir[2]);
185 bin2hex(eir + 2, 16, str, sizeof(str));
186 print("SSP Hash C-192: %s", str);
189 bin2hex(eir + 2, 16, str, sizeof(str));
190 print("SSP Rand R-192: %s", str);
193 ba2str((bdaddr_t *) (eir + 2), str);
194 print("LE Device Address: %s (%s)", str,
195 eir[8] ? "random" : "public");
198 print("LE Role: 0x%02x", eir[2]);
201 bin2hex(eir + 2, 16, str, sizeof(str));
202 print("SSP Hash C-256: %s", str);
205 bin2hex(eir + 2, 16, str, sizeof(str));
206 print("SSP Rand R-256: %s", str);
209 bin2hex(eir + 2, 16, str, sizeof(str));
210 print("LE SC Confirmation Value: %s", str);
213 bin2hex(eir + 2, 16, str, sizeof(str));
214 print("LE SC Random Value: %s", str);
217 print("Type %u: %u byte%s", eir[1], field_len - 1,
218 (field_len - 1) == 1 ? "" : "s");
222 eir += field_len + 1;
226 static bool load_identity(uint16_t index, struct mgmt_irk_info *irk)
228 char identity_path[PATH_MAX];
234 snprintf(identity_path, sizeof(identity_path),
235 "/sys/kernel/debug/bluetooth/hci%u/identity", index);
237 fp = fopen(identity_path, "r");
239 error("Failed to open identity file: %s", strerror(errno));
243 n = fscanf(fp, "%m[0-9a-f:] (type %u) %m[0-9a-f]", &addr, &type, &key);
250 str2ba(addr, &irk->addr.bdaddr);
251 hex2bin(key, irk->val, sizeof(irk->val));
258 irk->addr.type = BDADDR_LE_PUBLIC;
261 irk->addr.type = BDADDR_LE_RANDOM;
264 error("Invalid address type %u", type);
271 static void controller_error(uint16_t index, uint16_t len,
272 const void *param, void *user_data)
274 const struct mgmt_ev_controller_error *ev = param;
276 if (len < sizeof(*ev)) {
277 error("Too short (%u bytes) controller error event", len);
281 print("hci%u error 0x%02x", index, ev->error_code);
284 static void index_added(uint16_t index, uint16_t len,
285 const void *param, void *user_data)
287 print("hci%u added", index);
290 static void index_removed(uint16_t index, uint16_t len,
291 const void *param, void *user_data)
293 print("hci%u removed", index);
296 static void unconf_index_added(uint16_t index, uint16_t len,
297 const void *param, void *user_data)
299 print("hci%u added (unconfigured)", index);
302 static void unconf_index_removed(uint16_t index, uint16_t len,
303 const void *param, void *user_data)
305 print("hci%u removed (unconfigured)", index);
308 static void ext_index_added(uint16_t index, uint16_t len,
309 const void *param, void *user_data)
311 const struct mgmt_ev_ext_index_added *ev = param;
313 print("hci%u added (type %u bus %u)", index, ev->type, ev->bus);
316 static void ext_index_removed(uint16_t index, uint16_t len,
317 const void *param, void *user_data)
319 const struct mgmt_ev_ext_index_removed *ev = param;
321 print("hci%u removed (type %u bus %u)", index, ev->type, ev->bus);
324 static const char *options_str[] = {
329 static const char *options2str(uint32_t options)
331 static char str[256];
338 for (i = 0; i < NELEM(options_str); i++) {
339 if ((options & (1 << i)) != 0)
340 off += snprintf(str + off, sizeof(str) - off, "%s ",
347 static void new_config_options(uint16_t index, uint16_t len,
348 const void *param, void *user_data)
350 const uint32_t *ev = param;
352 if (len < sizeof(*ev)) {
353 error("Too short new_config_options event (%u)", len);
357 print("hci%u new_config_options: %s", index, options2str(get_le32(ev)));
360 static const char *settings_str[] = {
379 static const char *settings2str(uint32_t settings)
381 static char str[256];
388 for (i = 0; i < NELEM(settings_str); i++) {
389 if ((settings & (1 << i)) != 0)
390 off += snprintf(str + off, sizeof(str) - off, "%s ",
397 static void new_settings(uint16_t index, uint16_t len,
398 const void *param, void *user_data)
400 const uint32_t *ev = param;
402 if (len < sizeof(*ev)) {
403 error("Too short new_settings event (%u)", len);
407 print("hci%u new_settings: %s", index, settings2str(get_le32(ev)));
410 static void discovering(uint16_t index, uint16_t len, const void *param,
413 const struct mgmt_ev_discovering *ev = param;
415 if (len < sizeof(*ev)) {
416 error("Too short (%u bytes) discovering event", len);
420 print("hci%u type %u discovering %s", index, ev->type,
421 ev->discovering ? "on" : "off");
423 if (ev->discovering == 0 && discovery)
424 return noninteractive_quit(EXIT_SUCCESS);
427 static void new_link_key(uint16_t index, uint16_t len, const void *param,
430 const struct mgmt_ev_new_link_key *ev = param;
433 if (len != sizeof(*ev)) {
434 error("Invalid new_link_key length (%u bytes)", len);
438 ba2str(&ev->key.addr.bdaddr, addr);
439 print("hci%u new_link_key %s type 0x%02x pin_len %d store_hint %u",
440 index, addr, ev->key.type, ev->key.pin_len, ev->store_hint);
443 static const char *typestr(uint8_t type)
445 static const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
447 if (type <= BDADDR_LE_RANDOM)
453 static void connected(uint16_t index, uint16_t len, const void *param,
456 const struct mgmt_ev_device_connected *ev = param;
460 if (len < sizeof(*ev)) {
461 error("Invalid connected event length (%u bytes)", len);
465 eir_len = get_le16(&ev->eir_len);
466 if (len != sizeof(*ev) + eir_len) {
467 error("Invalid connected event length (%u != eir_len %u)",
472 ba2str(&ev->addr.bdaddr, addr);
473 print("hci%u %s type %s connected eir_len %u", index, addr,
474 typestr(ev->addr.type), eir_len);
477 static void release_prompt(void)
482 memset(&prompt, 0, sizeof(prompt));
483 prompt.index = MGMT_INDEX_NONE;
488 /* This will cause rl_expand_prompt to re-run over the last prompt,
489 * but our prompt doesn't expand anyway.
491 rl_set_prompt(saved_prompt);
492 rl_replace_line("", 0);
493 rl_point = saved_point;
500 static void disconnected(uint16_t index, uint16_t len, const void *param,
503 const struct mgmt_ev_device_disconnected *ev = param;
507 if (len < sizeof(struct mgmt_addr_info)) {
508 error("Invalid disconnected event length (%u bytes)", len);
512 if (!memcmp(&ev->addr, &prompt.addr, sizeof(ev->addr)))
515 if (len < sizeof(*ev))
516 reason = MGMT_DEV_DISCONN_UNKNOWN;
520 ba2str(&ev->addr.bdaddr, addr);
521 print("hci%u %s type %s disconnected with reason %u",
522 index, addr, typestr(ev->addr.type), reason);
525 static void conn_failed(uint16_t index, uint16_t len, const void *param,
528 const struct mgmt_ev_connect_failed *ev = param;
531 if (len != sizeof(*ev)) {
532 error("Invalid connect_failed event length (%u bytes)", len);
536 ba2str(&ev->addr.bdaddr, addr);
537 print("hci%u %s type %s connect failed (status 0x%02x, %s)",
538 index, addr, typestr(ev->addr.type), ev->status,
539 mgmt_errstr(ev->status));
542 static void auth_failed(uint16_t index, uint16_t len, const void *param,
545 const struct mgmt_ev_auth_failed *ev = param;
548 if (len != sizeof(*ev)) {
549 error("Invalid auth_failed event length (%u bytes)", len);
553 if (!memcmp(&ev->addr, &prompt.addr, sizeof(ev->addr)))
556 ba2str(&ev->addr.bdaddr, addr);
557 print("hci%u %s auth failed with status 0x%02x (%s)",
558 index, addr, ev->status, mgmt_errstr(ev->status));
561 static void class_of_dev_changed(uint16_t index, uint16_t len,
562 const void *param, void *user_data)
564 const struct mgmt_ev_class_of_dev_changed *ev = param;
566 if (len != sizeof(*ev)) {
567 error("Invalid class_of_dev_changed length (%u bytes)", len);
571 print("hci%u class of device changed: 0x%02x%02x%02x", index,
572 ev->dev_class[2], ev->dev_class[1], ev->dev_class[0]);
575 static void local_name_changed(uint16_t index, uint16_t len, const void *param,
578 const struct mgmt_ev_local_name_changed *ev = param;
580 if (len != sizeof(*ev)) {
581 error("Invalid local_name_changed length (%u bytes)", len);
585 print("hci%u name changed: %s", index, ev->name);
588 static void confirm_name_rsp(uint8_t status, uint16_t len,
589 const void *param, void *user_data)
591 const struct mgmt_rp_confirm_name *rp = param;
594 if (len == 0 && status != 0) {
595 error("confirm_name failed with status 0x%02x (%s)", status,
596 mgmt_errstr(status));
600 if (len != sizeof(*rp)) {
601 error("confirm_name rsp length %u instead of %zu",
606 ba2str(&rp->addr.bdaddr, addr);
609 error("confirm_name for %s failed: 0x%02x (%s)",
610 addr, status, mgmt_errstr(status));
612 print("confirm_name succeeded for %s", addr);
615 static char *eir_get_name(const uint8_t *eir, uint16_t eir_len)
622 while (parsed < eir_len - 1) {
623 uint8_t field_len = eir[0];
628 parsed += field_len + 1;
630 if (parsed > eir_len)
633 /* Check for short of complete name */
634 if (eir[1] == 0x09 || eir[1] == 0x08)
635 return strndup((char *) &eir[2], field_len - 1);
637 eir += field_len + 1;
643 static unsigned int eir_get_flags(const uint8_t *eir, uint16_t eir_len)
650 while (parsed < eir_len - 1) {
651 uint8_t field_len = eir[0];
656 parsed += field_len + 1;
658 if (parsed > eir_len)
661 /* Check for flags */
665 eir += field_len + 1;
671 static void device_found(uint16_t index, uint16_t len, const void *param,
674 const struct mgmt_ev_device_found *ev = param;
675 struct mgmt *mgmt = user_data;
679 if (len < sizeof(*ev)) {
680 error("Too short device_found length (%u bytes)", len);
684 flags = btohl(ev->flags);
686 eir_len = get_le16(&ev->eir_len);
687 if (len != sizeof(*ev) + eir_len) {
688 error("dev_found: expected %zu bytes, got %u bytes",
689 sizeof(*ev) + eir_len, len);
694 char addr[18], *name;
696 ba2str(&ev->addr.bdaddr, addr);
697 print("hci%u dev_found: %s type %s rssi %d "
698 "flags 0x%04x ", index, addr,
699 typestr(ev->addr.type), ev->rssi, flags);
701 if (ev->addr.type != BDADDR_BREDR)
702 print("AD flags 0x%02x ",
703 eir_get_flags(ev->eir, eir_len));
705 name = eir_get_name(ev->eir, eir_len);
707 print("name %s", name);
709 print("eir_len %u", eir_len);
714 if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) {
715 struct mgmt_cp_confirm_name cp;
717 memset(&cp, 0, sizeof(cp));
718 memcpy(&cp.addr, &ev->addr, sizeof(cp.addr));
724 mgmt_reply(mgmt, MGMT_OP_CONFIRM_NAME, index, sizeof(cp), &cp,
725 confirm_name_rsp, NULL, NULL);
729 static void pin_rsp(uint8_t status, uint16_t len, const void *param,
733 error("PIN Code reply failed with status 0x%02x (%s)",
734 status, mgmt_errstr(status));
735 return noninteractive_quit(EXIT_FAILURE);
738 print("PIN Reply successful");
741 static int mgmt_pin_reply(struct mgmt *mgmt, uint16_t index,
742 const struct mgmt_addr_info *addr,
743 const char *pin, size_t len)
745 struct mgmt_cp_pin_code_reply cp;
747 memset(&cp, 0, sizeof(cp));
748 memcpy(&cp.addr, addr, sizeof(cp.addr));
750 memcpy(cp.pin_code, pin, len);
752 return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_REPLY, index, sizeof(cp), &cp,
753 pin_rsp, NULL, NULL);
756 static void pin_neg_rsp(uint8_t status, uint16_t len, const void *param,
760 error("PIN Neg reply failed with status 0x%02x (%s)",
761 status, mgmt_errstr(status));
762 return noninteractive_quit(EXIT_FAILURE);
765 print("PIN Negative Reply successful");
768 static int mgmt_pin_neg_reply(struct mgmt *mgmt, uint16_t index,
769 const struct mgmt_addr_info *addr)
771 struct mgmt_cp_pin_code_neg_reply cp;
773 memset(&cp, 0, sizeof(cp));
774 memcpy(&cp.addr, addr, sizeof(cp.addr));
776 return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_NEG_REPLY, index,
777 sizeof(cp), &cp, pin_neg_rsp, NULL, NULL);
780 static void confirm_rsp(uint8_t status, uint16_t len, const void *param,
784 error("User Confirm reply failed. status 0x%02x (%s)",
785 status, mgmt_errstr(status));
786 return noninteractive_quit(EXIT_FAILURE);
789 print("User Confirm Reply successful");
792 static int mgmt_confirm_reply(struct mgmt *mgmt, uint16_t index,
793 const struct mgmt_addr_info *addr)
795 struct mgmt_cp_user_confirm_reply cp;
797 memset(&cp, 0, sizeof(cp));
798 memcpy(&cp.addr, addr, sizeof(*addr));
800 return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_REPLY, index,
801 sizeof(cp), &cp, confirm_rsp, NULL, NULL);
804 static void confirm_neg_rsp(uint8_t status, uint16_t len, const void *param,
808 error("Confirm Neg reply failed. status 0x%02x (%s)",
809 status, mgmt_errstr(status));
810 return noninteractive_quit(EXIT_FAILURE);
813 print("User Confirm Negative Reply successful");
816 static int mgmt_confirm_neg_reply(struct mgmt *mgmt, uint16_t index,
817 const struct mgmt_addr_info *addr)
819 struct mgmt_cp_user_confirm_reply cp;
821 memset(&cp, 0, sizeof(cp));
822 memcpy(&cp.addr, addr, sizeof(*addr));
824 return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_NEG_REPLY, index,
825 sizeof(cp), &cp, confirm_neg_rsp, NULL, NULL);
828 static void passkey_rsp(uint8_t status, uint16_t len, const void *param,
832 error("User Passkey reply failed. status 0x%02x (%s)",
833 status, mgmt_errstr(status));
834 return noninteractive_quit(EXIT_FAILURE);
837 print("User Passkey Reply successful");
840 static int mgmt_passkey_reply(struct mgmt *mgmt, uint16_t index,
841 const struct mgmt_addr_info *addr,
844 struct mgmt_cp_user_passkey_reply cp;
846 memset(&cp, 0, sizeof(cp));
847 memcpy(&cp.addr, addr, sizeof(*addr));
848 put_le32(passkey, &cp.passkey);
850 return mgmt_reply(mgmt, MGMT_OP_USER_PASSKEY_REPLY, index,
851 sizeof(cp), &cp, passkey_rsp, NULL, NULL);
854 static void passkey_neg_rsp(uint8_t status, uint16_t len, const void *param,
858 error("Passkey Neg reply failed. status 0x%02x (%s)",
859 status, mgmt_errstr(status));
860 return noninteractive_quit(EXIT_FAILURE);
863 print("User Passkey Negative Reply successful");
866 static int mgmt_passkey_neg_reply(struct mgmt *mgmt, uint16_t index,
867 const struct mgmt_addr_info *addr)
869 struct mgmt_cp_user_passkey_reply cp;
871 memset(&cp, 0, sizeof(cp));
872 memcpy(&cp.addr, addr, sizeof(*addr));
874 return mgmt_reply(mgmt, MGMT_OP_USER_PASSKEY_NEG_REPLY, index,
875 sizeof(cp), &cp, passkey_neg_rsp, NULL, NULL);
878 static bool prompt_input(const char *input)
887 switch (prompt.req) {
888 case MGMT_EV_PIN_CODE_REQUEST:
890 mgmt_pin_reply(mgmt, prompt.index, &prompt.addr,
893 mgmt_pin_neg_reply(mgmt, prompt.index, &prompt.addr);
895 case MGMT_EV_USER_PASSKEY_REQUEST:
896 if (strlen(input) > 0)
897 mgmt_passkey_reply(mgmt, prompt.index, &prompt.addr,
900 mgmt_passkey_neg_reply(mgmt, prompt.index,
903 case MGMT_EV_USER_CONFIRM_REQUEST:
904 if (input[0] == 'y' || input[0] == 'Y')
905 mgmt_confirm_reply(mgmt, prompt.index, &prompt.addr);
907 mgmt_confirm_neg_reply(mgmt, prompt.index,
917 static void interactive_prompt(const char *msg)
922 saved_prompt = strdup(rl_prompt);
926 saved_point = rl_point;
933 rl_replace_line("", 0);
937 static size_t get_input(char *buf, size_t buf_len)
941 if (!fgets(buf, buf_len, stdin))
946 /* Remove trailing white-space */
947 while (len && isspace(buf[len - 1]))
953 static void ask(uint16_t index, uint16_t req, const struct mgmt_addr_info *addr,
954 const char *fmt, ...)
956 char msg[256], buf[18];
960 prompt.index = index;
962 memcpy(&prompt.addr, addr, sizeof(*addr));
965 off = vsnprintf(msg, sizeof(msg), fmt, ap);
968 snprintf(msg + off, sizeof(msg) - off, " %s ",
969 COLOR_BOLDGRAY ">>" COLOR_OFF);
972 interactive_prompt(msg);
980 memset(buf, 0, sizeof(buf));
981 get_input(buf, sizeof(buf));
985 static void request_pin(uint16_t index, uint16_t len, const void *param,
988 const struct mgmt_ev_pin_code_request *ev = param;
991 if (len != sizeof(*ev)) {
992 error("Invalid pin_code request length (%u bytes)", len);
996 ba2str(&ev->addr.bdaddr, addr);
997 print("hci%u %s request PIN", index, addr);
999 ask(index, MGMT_EV_PIN_CODE_REQUEST, &ev->addr,
1000 "PIN Request (press enter to reject)");
1003 static void user_confirm(uint16_t index, uint16_t len, const void *param,
1006 const struct mgmt_ev_user_confirm_request *ev = param;
1010 if (len != sizeof(*ev)) {
1011 error("Invalid user_confirm request length (%u)", len);
1015 ba2str(&ev->addr.bdaddr, addr);
1016 val = get_le32(&ev->value);
1018 print("hci%u %s User Confirm %06u hint %u", index, addr,
1019 val, ev->confirm_hint);
1021 if (ev->confirm_hint)
1022 ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr,
1023 "Accept pairing with %s (yes/no)", addr);
1025 ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr,
1026 "Confirm value %06u for %s (yes/no)", val, addr);
1029 static void request_passkey(uint16_t index, uint16_t len, const void *param,
1032 const struct mgmt_ev_user_passkey_request *ev = param;
1035 if (len != sizeof(*ev)) {
1036 error("Invalid passkey request length (%u bytes)", len);
1040 ba2str(&ev->addr.bdaddr, addr);
1041 print("hci%u %s request passkey", index, addr);
1043 ask(index, MGMT_EV_USER_PASSKEY_REQUEST, &ev->addr,
1044 "Passkey Request (press enter to reject)");
1047 static void passkey_notify(uint16_t index, uint16_t len, const void *param,
1050 const struct mgmt_ev_passkey_notify *ev = param;
1053 if (len != sizeof(*ev)) {
1054 error("Invalid passkey request length (%u bytes)", len);
1058 ba2str(&ev->addr.bdaddr, addr);
1059 print("hci%u %s request passkey", index, addr);
1061 print("Passkey Notify: %06u (entered %u)", get_le32(&ev->passkey),
1065 static void local_oob_data_updated(uint16_t index, uint16_t len,
1066 const void *param, void *user_data)
1068 const struct mgmt_ev_local_oob_data_updated *ev = param;
1071 if (len < sizeof(*ev)) {
1072 error("Too small (%u bytes) local_oob_updated event", len);
1076 eir_len = le16_to_cpu(ev->eir_len);
1077 if (len != sizeof(*ev) + eir_len) {
1078 error("local_oob_updated: expected %zu bytes, got %u bytes",
1079 sizeof(*ev) + eir_len, len);
1083 print("hci%u oob data updated: type %u len %u", index,
1087 static void advertising_added(uint16_t index, uint16_t len,
1088 const void *param, void *user_data)
1090 const struct mgmt_ev_advertising_added *ev = param;
1092 if (len < sizeof(*ev)) {
1093 error("Too small (%u bytes) advertising_added event", len);
1097 print("hci%u advertising_added: instance %u", index, ev->instance);
1100 static void advertising_removed(uint16_t index, uint16_t len,
1101 const void *param, void *user_data)
1103 const struct mgmt_ev_advertising_removed *ev = param;
1105 if (len < sizeof(*ev)) {
1106 error("Too small (%u bytes) advertising_removed event", len);
1110 print("hci%u advertising_removed: instance %u", index, ev->instance);
1113 static void version_rsp(uint8_t status, uint16_t len, const void *param,
1116 const struct mgmt_rp_read_version *rp = param;
1119 error("Reading mgmt version failed with status 0x%02x (%s)",
1120 status, mgmt_errstr(status));
1124 if (len < sizeof(*rp)) {
1125 error("Too small version reply (%u bytes)", len);
1129 print("MGMT Version %u, revision %u", rp->version,
1130 get_le16(&rp->revision));
1133 noninteractive_quit(EXIT_SUCCESS);
1136 static void cmd_version(struct mgmt *mgmt, uint16_t index, int argc,
1139 if (mgmt_send(mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE,
1140 0, NULL, version_rsp, NULL, NULL) == 0) {
1141 error("Unable to send read_version cmd");
1142 return noninteractive_quit(EXIT_FAILURE);
1146 static void commands_rsp(uint8_t status, uint16_t len, const void *param,
1149 const struct mgmt_rp_read_commands *rp = param;
1150 uint16_t num_commands, num_events;
1151 const uint16_t *opcode;
1152 size_t expected_len;
1156 error("Read Supported Commands failed: status 0x%02x (%s)",
1157 status, mgmt_errstr(status));
1161 if (len < sizeof(*rp)) {
1162 error("Too small commands reply (%u bytes)", len);
1166 num_commands = get_le16(&rp->num_commands);
1167 num_events = get_le16(&rp->num_events);
1169 expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
1170 num_events * sizeof(uint16_t);
1172 if (len < expected_len) {
1173 error("Too small commands reply (%u != %zu)",
1178 opcode = rp->opcodes;
1180 print("%u commands:", num_commands);
1181 for (i = 0; i < num_commands; i++) {
1182 uint16_t op = get_le16(opcode++);
1183 print("\t%s (0x%04x)", mgmt_opstr(op), op);
1186 print("%u events:", num_events);
1187 for (i = 0; i < num_events; i++) {
1188 uint16_t ev = get_le16(opcode++);
1189 print("\t%s (0x%04x)", mgmt_evstr(ev), ev);
1193 noninteractive_quit(EXIT_SUCCESS);
1196 static void cmd_commands(struct mgmt *mgmt, uint16_t index, int argc,
1199 if (mgmt_send(mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE,
1200 0, NULL, commands_rsp, NULL, NULL) == 0) {
1201 error("Unable to send read_commands cmd");
1202 return noninteractive_quit(EXIT_FAILURE);
1206 static void config_info_rsp(uint8_t status, uint16_t len, const void *param,
1209 const struct mgmt_rp_read_config_info *rp = param;
1210 uint16_t index = PTR_TO_UINT(user_data);
1211 uint32_t supported_options, missing_options;
1214 error("Reading hci%u config failed with status 0x%02x (%s)",
1215 index, status, mgmt_errstr(status));
1219 if (len < sizeof(*rp)) {
1220 error("Too small info reply (%u bytes)", len);
1224 print("hci%u:\tUnconfigured controller", index);
1226 print("\tmanufacturer %u", le16_to_cpu(rp->manufacturer));
1228 supported_options = le32_to_cpu(rp->supported_options);
1229 print("\tsupported options: %s", options2str(supported_options));
1231 missing_options = le32_to_cpu(rp->missing_options);
1232 print("\tmissing options: %s", options2str(missing_options));
1237 if (pending_index > 0)
1240 noninteractive_quit(EXIT_SUCCESS);
1243 static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param,
1246 const struct mgmt_rp_read_unconf_index_list *rp = param;
1251 error("Reading index list failed with status 0x%02x (%s)",
1252 status, mgmt_errstr(status));
1253 return noninteractive_quit(EXIT_FAILURE);
1256 if (len < sizeof(*rp)) {
1257 error("Too small index list reply (%u bytes)", len);
1258 return noninteractive_quit(EXIT_FAILURE);
1261 count = le16_to_cpu(rp->num_controllers);
1263 if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
1264 error("Index count (%u) doesn't match reply length (%u)",
1266 return noninteractive_quit(EXIT_FAILURE);
1269 print("Unconfigured index list with %u item%s",
1270 count, count != 1 ? "s" : "");
1272 for (i = 0; i < count; i++) {
1273 uint16_t index = le16_to_cpu(rp->index[i]);
1275 if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL,
1276 config_info_rsp, UINT_TO_PTR(index), NULL)) {
1277 error("Unable to send read_config_info cmd");
1278 return noninteractive_quit(EXIT_FAILURE);
1285 noninteractive_quit(EXIT_SUCCESS);
1288 static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1290 if (index == MGMT_INDEX_NONE) {
1291 if (!mgmt_send(mgmt, MGMT_OP_READ_UNCONF_INDEX_LIST,
1292 MGMT_INDEX_NONE, 0, NULL,
1293 unconf_index_rsp, mgmt, NULL)) {
1294 error("Unable to send unconf_index_list cmd");
1295 return noninteractive_quit(EXIT_FAILURE);
1301 if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL,
1302 config_info_rsp, UINT_TO_PTR(index), NULL)) {
1303 error("Unable to send read_config_info cmd");
1304 return noninteractive_quit(EXIT_FAILURE);
1308 static void config_options_rsp(uint8_t status, uint16_t len, const void *param,
1311 const struct mgmt_rp_read_config_info *rp = param;
1312 uint16_t index = PTR_TO_UINT(user_data);
1313 uint32_t supported_options, missing_options;
1316 error("Reading hci%u config failed with status 0x%02x (%s)",
1317 index, status, mgmt_errstr(status));
1321 if (len < sizeof(*rp)) {
1322 error("Too small info reply (%u bytes)", len);
1326 print("hci%u:\tConfiguration options", index);
1328 supported_options = le32_to_cpu(rp->supported_options);
1329 print("\tsupported options: %s", options2str(supported_options));
1331 missing_options = le32_to_cpu(rp->missing_options);
1332 print("\tmissing options: %s", options2str(missing_options));
1337 if (pending_index > 0)
1340 noninteractive_quit(EXIT_SUCCESS);
1343 static void info_rsp(uint8_t status, uint16_t len, const void *param,
1346 const struct mgmt_rp_read_info *rp = param;
1347 uint16_t index = PTR_TO_UINT(user_data);
1348 uint32_t supported_settings, current_settings;
1352 error("Reading hci%u info failed with status 0x%02x (%s)",
1353 index, status, mgmt_errstr(status));
1357 if (len < sizeof(*rp)) {
1358 error("Too small info reply (%u bytes)", len);
1362 print("hci%u:\tPrimary controller", index);
1364 ba2str(&rp->bdaddr, addr);
1365 print("\taddr %s version %u manufacturer %u class 0x%02x%02x%02x",
1366 addr, rp->version, le16_to_cpu(rp->manufacturer),
1367 rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
1369 supported_settings = le32_to_cpu(rp->supported_settings);
1370 print("\tsupported settings: %s", settings2str(supported_settings));
1372 current_settings = le32_to_cpu(rp->current_settings);
1373 print("\tcurrent settings: %s", settings2str(current_settings));
1375 print("\tname %s", rp->name);
1376 print("\tshort name %s", rp->short_name);
1378 if (supported_settings & MGMT_SETTING_CONFIGURATION) {
1379 if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO,
1380 index, 0, NULL, config_options_rsp,
1381 UINT_TO_PTR(index), NULL)) {
1382 error("Unable to send read_config cmd");
1391 if (pending_index > 0)
1394 noninteractive_quit(EXIT_SUCCESS);
1397 static void index_rsp(uint8_t status, uint16_t len, const void *param,
1400 const struct mgmt_rp_read_index_list *rp = param;
1401 struct mgmt *mgmt = user_data;
1406 error("Reading index list failed with status 0x%02x (%s)",
1407 status, mgmt_errstr(status));
1408 return noninteractive_quit(EXIT_FAILURE);
1411 if (len < sizeof(*rp)) {
1412 error("Too small index list reply (%u bytes)", len);
1413 return noninteractive_quit(EXIT_FAILURE);
1416 count = le16_to_cpu(rp->num_controllers);
1418 if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
1419 error("Index count (%u) doesn't match reply length (%u)",
1421 return noninteractive_quit(EXIT_FAILURE);
1424 print("Index list with %u item%s", count, count != 1 ? "s" : "");
1426 for (i = 0; i < count; i++) {
1427 uint16_t index = le16_to_cpu(rp->index[i]);
1429 if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
1430 info_rsp, UINT_TO_PTR(index), NULL)) {
1431 error("Unable to send read_info cmd");
1432 return noninteractive_quit(EXIT_FAILURE);
1439 noninteractive_quit(EXIT_SUCCESS);
1442 static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1444 if (index == MGMT_INDEX_NONE) {
1445 if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST,
1446 MGMT_INDEX_NONE, 0, NULL,
1447 index_rsp, mgmt, NULL)) {
1448 error("Unable to send index_list cmd");
1449 return noninteractive_quit(EXIT_FAILURE);
1455 if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, info_rsp,
1456 UINT_TO_PTR(index), NULL)) {
1457 error("Unable to send read_info cmd");
1458 return noninteractive_quit(EXIT_FAILURE);
1462 static void ext_index_rsp(uint8_t status, uint16_t len, const void *param,
1465 const struct mgmt_rp_read_ext_index_list *rp = param;
1466 uint16_t count, index_filter = PTR_TO_UINT(user_data);
1470 error("Reading ext index list failed with status 0x%02x (%s)",
1471 status, mgmt_errstr(status));
1472 return noninteractive_quit(EXIT_FAILURE);
1475 if (len < sizeof(*rp)) {
1476 error("Too small ext index list reply (%u bytes)", len);
1477 return noninteractive_quit(EXIT_FAILURE);
1480 count = get_le16(&rp->num_controllers);
1482 if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) {
1483 error("Index count (%u) doesn't match reply length (%u)",
1485 return noninteractive_quit(EXIT_FAILURE);
1488 print("Extended index list with %u item%s",
1489 count, count != 1 ? "s" : "");
1491 for (i = 0; i < count; i++) {
1492 uint16_t index = le16_to_cpu(rp->entry[i].index);
1493 char *busstr = hci_bustostr(rp->entry[i].bus);
1495 if (index_filter != MGMT_INDEX_NONE && index_filter != index)
1498 switch (rp->entry[i].type) {
1500 print("Primary controller (hci%u,%s)", index, busstr);
1501 if (!mgmt_send(mgmt, MGMT_OP_READ_INFO,
1502 index, 0, NULL, info_rsp,
1503 UINT_TO_PTR(index), NULL)) {
1504 error("Unable to send read_info cmd");
1505 return noninteractive_quit(EXIT_FAILURE);
1510 print("Unconfigured controller (hci%u,%s)",
1512 if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO,
1513 index, 0, NULL, config_info_rsp,
1514 UINT_TO_PTR(index), NULL)) {
1515 error("Unable to send read_config cmd");
1516 return noninteractive_quit(EXIT_FAILURE);
1521 print("AMP controller (hci%u,%s)", index, busstr);
1524 print("Type %u controller (hci%u,%s)",
1525 rp->entry[i].type, index, busstr);
1533 noninteractive_quit(EXIT_SUCCESS);
1536 static void cmd_extinfo(struct mgmt *mgmt, uint16_t index,
1537 int argc, char **argv)
1539 if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST,
1540 MGMT_INDEX_NONE, 0, NULL,
1541 ext_index_rsp, UINT_TO_PTR(index), NULL)) {
1542 error("Unable to send ext_index_list cmd");
1543 return noninteractive_quit(EXIT_FAILURE);
1547 static void auto_power_enable_rsp(uint8_t status, uint16_t len,
1548 const void *param, void *user_data)
1550 uint16_t index = PTR_TO_UINT(user_data);
1552 print("Successfully enabled controller with index %u", index);
1554 noninteractive_quit(EXIT_SUCCESS);
1557 static void auto_power_info_rsp(uint8_t status, uint16_t len,
1558 const void *param, void *user_data)
1560 const struct mgmt_rp_read_info *rp = param;
1561 uint16_t index = PTR_TO_UINT(user_data);
1562 uint32_t supported_settings, current_settings, missing_settings;
1566 error("Reading info failed with status 0x%02x (%s)",
1567 status, mgmt_errstr(status));
1568 return noninteractive_quit(EXIT_FAILURE);
1571 supported_settings = le32_to_cpu(rp->supported_settings);
1572 current_settings = le32_to_cpu(rp->current_settings);
1573 missing_settings = current_settings ^ supported_settings;
1575 if (missing_settings & MGMT_SETTING_BREDR)
1576 mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, sizeof(val), &val,
1579 if (missing_settings & MGMT_SETTING_SSP)
1580 mgmt_send(mgmt, MGMT_OP_SET_SSP, index, sizeof(val), &val,
1583 if (missing_settings & MGMT_SETTING_LE)
1584 mgmt_send(mgmt, MGMT_OP_SET_LE, index, sizeof(val), &val,
1587 if (missing_settings & MGMT_SETTING_SECURE_CONN)
1588 mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index,
1592 if (missing_settings & MGMT_SETTING_BONDABLE)
1593 mgmt_send(mgmt, MGMT_OP_SET_BONDABLE, index, sizeof(val), &val,
1596 if (current_settings & MGMT_SETTING_POWERED)
1597 return noninteractive_quit(EXIT_SUCCESS);
1599 if (!mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, sizeof(val), &val,
1600 auto_power_enable_rsp,
1601 UINT_TO_PTR(index), NULL)) {
1602 error("Unable to send set powerd cmd");
1603 return noninteractive_quit(EXIT_FAILURE);
1607 static void auto_power_index_evt(uint16_t index, uint16_t len,
1608 const void *param, void *user_data)
1610 uint16_t index_filter = PTR_TO_UINT(user_data);
1612 if (index != index_filter)
1615 print("New controller with index %u", index);
1617 if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
1618 auto_power_info_rsp,
1619 UINT_TO_PTR(index), NULL)) {
1620 error("Unable to send read info cmd");
1621 return noninteractive_quit(EXIT_FAILURE);
1625 static void auto_power_index_rsp(uint8_t status, uint16_t len,
1626 const void *param, void *user_data)
1628 const struct mgmt_rp_read_index_list *rp = param;
1629 uint16_t index = PTR_TO_UINT(user_data);
1634 error("Reading index list failed with status 0x%02x (%s)",
1635 status, mgmt_errstr(status));
1636 return noninteractive_quit(EXIT_FAILURE);
1639 count = le16_to_cpu(rp->num_controllers);
1640 for (i = 0; i < count; i++) {
1641 if (le16_to_cpu(rp->index[i]) == index)
1646 print("Waiting for index %u to appear", index);
1648 mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index,
1649 auto_power_index_evt,
1650 UINT_TO_PTR(index), NULL);
1654 print("Found controller with index %u", index);
1656 if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
1657 auto_power_info_rsp,
1658 UINT_TO_PTR(index), NULL)) {
1659 error("Unable to send read info cmd");
1660 return noninteractive_quit(EXIT_FAILURE);
1664 static void cmd_auto_power(struct mgmt *mgmt, uint16_t index,
1665 int argc, char **argv)
1667 if (index == MGMT_INDEX_NONE)
1670 if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
1671 auto_power_index_rsp,
1672 UINT_TO_PTR(index), NULL)) {
1673 error("Unable to send read index list cmd");
1674 return noninteractive_quit(EXIT_FAILURE);
1678 /* Wrapper to get the index and opcode to the response callback */
1679 struct command_data {
1682 void (*callback) (uint16_t id, uint16_t op, uint8_t status,
1683 uint16_t len, const void *param);
1686 static void cmd_rsp(uint8_t status, uint16_t len, const void *param,
1689 struct command_data *data = user_data;
1691 data->callback(data->op, data->id, status, len, param);
1694 static unsigned int send_cmd(struct mgmt *mgmt, uint16_t op, uint16_t id,
1695 uint16_t len, const void *param,
1696 void (*cb)(uint16_t id, uint16_t op,
1697 uint8_t status, uint16_t len,
1700 struct command_data *data;
1701 unsigned int send_id;
1703 data = new0(struct command_data, 1);
1709 data->callback = cb;
1711 send_id = mgmt_send(mgmt, op, id, len, param, cmd_rsp, data, free);
1718 static void setting_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
1721 const uint32_t *rp = param;
1724 error("%s for hci%u failed with status 0x%02x (%s)",
1725 mgmt_opstr(op), id, status, mgmt_errstr(status));
1729 if (len < sizeof(*rp)) {
1730 error("Too small %s response (%u bytes)",
1731 mgmt_opstr(op), len);
1735 print("hci%u %s complete, settings: %s", id, mgmt_opstr(op),
1736 settings2str(get_le32(rp)));
1739 noninteractive_quit(EXIT_SUCCESS);
1742 static void cmd_setting(struct mgmt *mgmt, uint16_t index, uint16_t op,
1743 int argc, char **argv)
1748 print("Specify \"on\" or \"off\"");
1749 return noninteractive_quit(EXIT_FAILURE);
1752 if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
1754 else if (strcasecmp(argv[1], "off") == 0)
1757 val = atoi(argv[1]);
1759 if (index == MGMT_INDEX_NONE)
1762 if (send_cmd(mgmt, op, index, sizeof(val), &val, setting_rsp) == 0) {
1763 error("Unable to send %s cmd", mgmt_opstr(op));
1764 return noninteractive_quit(EXIT_FAILURE);
1768 static void cmd_power(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1770 cmd_setting(mgmt, index, MGMT_OP_SET_POWERED, argc, argv);
1773 static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc,
1776 struct mgmt_cp_set_discoverable cp;
1779 print("Usage: %s <yes/no/limited> [timeout]", argv[0]);
1780 return noninteractive_quit(EXIT_FAILURE);
1783 memset(&cp, 0, sizeof(cp));
1785 if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
1787 else if (strcasecmp(argv[1], "off") == 0)
1789 else if (strcasecmp(argv[1], "limited") == 0)
1792 cp.val = atoi(argv[1]);
1795 cp.timeout = htobs(atoi(argv[2]));
1797 if (index == MGMT_INDEX_NONE)
1800 if (send_cmd(mgmt, MGMT_OP_SET_DISCOVERABLE, index, sizeof(cp), &cp,
1801 setting_rsp) == 0) {
1802 error("Unable to send set_discoverable cmd");
1803 return noninteractive_quit(EXIT_FAILURE);
1807 static void cmd_connectable(struct mgmt *mgmt, uint16_t index, int argc,
1810 cmd_setting(mgmt, index, MGMT_OP_SET_CONNECTABLE, argc, argv);
1813 static void cmd_fast_conn(struct mgmt *mgmt, uint16_t index, int argc,
1816 cmd_setting(mgmt, index, MGMT_OP_SET_FAST_CONNECTABLE, argc, argv);
1819 static void cmd_bondable(struct mgmt *mgmt, uint16_t index, int argc,
1822 cmd_setting(mgmt, index, MGMT_OP_SET_BONDABLE, argc, argv);
1825 static void cmd_linksec(struct mgmt *mgmt, uint16_t index, int argc,
1828 cmd_setting(mgmt, index, MGMT_OP_SET_LINK_SECURITY, argc, argv);
1831 static void cmd_ssp(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1833 cmd_setting(mgmt, index, MGMT_OP_SET_SSP, argc, argv);
1836 static void cmd_sc(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1841 print("Specify \"on\" or \"off\" or \"only\"");
1842 return noninteractive_quit(EXIT_FAILURE);
1845 if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
1847 else if (strcasecmp(argv[1], "off") == 0)
1849 else if (strcasecmp(argv[1], "only") == 0)
1852 val = atoi(argv[1]);
1854 if (index == MGMT_INDEX_NONE)
1857 if (send_cmd(mgmt, MGMT_OP_SET_SECURE_CONN, index,
1858 sizeof(val), &val, setting_rsp) == 0) {
1859 error("Unable to send set_secure_conn cmd");
1860 return noninteractive_quit(EXIT_FAILURE);
1864 static void cmd_hs(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1866 cmd_setting(mgmt, index, MGMT_OP_SET_HS, argc, argv);
1869 static void cmd_le(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1871 cmd_setting(mgmt, index, MGMT_OP_SET_LE, argc, argv);
1874 static void cmd_advertising(struct mgmt *mgmt, uint16_t index, int argc,
1877 cmd_setting(mgmt, index, MGMT_OP_SET_ADVERTISING, argc, argv);
1880 static void cmd_bredr(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1882 cmd_setting(mgmt, index, MGMT_OP_SET_BREDR, argc, argv);
1885 static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc,
1888 struct mgmt_cp_set_privacy cp;
1891 print("Specify \"on\" or \"off\"");
1892 return noninteractive_quit(EXIT_FAILURE);
1895 if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
1897 else if (strcasecmp(argv[1], "off") == 0)
1900 cp.privacy = atoi(argv[1]);
1902 if (index == MGMT_INDEX_NONE)
1906 if (hex2bin(argv[2], cp.irk,
1907 sizeof(cp.irk)) != sizeof(cp.irk)) {
1908 error("Invalid key format");
1909 return noninteractive_quit(EXIT_FAILURE);
1914 fd = open("/dev/urandom", O_RDONLY);
1916 error("open(/dev/urandom): %s", strerror(errno));
1917 return noninteractive_quit(EXIT_FAILURE);
1920 if (read(fd, cp.irk, sizeof(cp.irk)) != sizeof(cp.irk)) {
1921 error("Reading from urandom failed");
1923 return noninteractive_quit(EXIT_FAILURE);
1929 if (send_cmd(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp,
1930 setting_rsp) == 0) {
1931 error("Unable to send Set Privacy command");
1932 return noninteractive_quit(EXIT_FAILURE);
1936 static void class_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
1939 const struct mgmt_ev_class_of_dev_changed *rp = param;
1941 if (len == 0 && status != 0) {
1942 error("%s failed, status 0x%02x (%s)",
1943 mgmt_opstr(op), status, mgmt_errstr(status));
1944 return noninteractive_quit(EXIT_FAILURE);
1947 if (len != sizeof(*rp)) {
1948 error("Unexpected %s len %u", mgmt_opstr(op), len);
1949 return noninteractive_quit(EXIT_FAILURE);
1952 print("%s succeeded. Class 0x%02x%02x%02x", mgmt_opstr(op),
1953 rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
1955 noninteractive_quit(EXIT_SUCCESS);
1958 static void cmd_class(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1963 print("Usage: %s <major> <minor>", argv[0]);
1964 return noninteractive_quit(EXIT_FAILURE);
1967 class[0] = atoi(argv[1]);
1968 class[1] = atoi(argv[2]);
1970 if (index == MGMT_INDEX_NONE)
1973 if (send_cmd(mgmt, MGMT_OP_SET_DEV_CLASS, index, sizeof(class), class,
1975 error("Unable to send set_dev_class cmd");
1976 return noninteractive_quit(EXIT_FAILURE);
1980 static void disconnect_rsp(uint8_t status, uint16_t len, const void *param,
1983 const struct mgmt_rp_disconnect *rp = param;
1986 if (len == 0 && status != 0) {
1987 error("Disconnect failed with status 0x%02x (%s)",
1988 status, mgmt_errstr(status));
1989 return noninteractive_quit(EXIT_FAILURE);
1992 if (len != sizeof(*rp)) {
1993 error("Invalid disconnect response length (%u)", len);
1994 return noninteractive_quit(EXIT_FAILURE);
1997 ba2str(&rp->addr.bdaddr, addr);
2000 print("%s disconnected", addr);
2002 error("Disconnecting %s failed with status 0x%02x (%s)",
2003 addr, status, mgmt_errstr(status));
2005 noninteractive_quit(EXIT_SUCCESS);
2008 static void disconnect_usage(void)
2010 print("Usage: disconnect [-t type] <remote address>");
2013 static struct option disconnect_options[] = {
2014 { "help", 0, 0, 'h' },
2015 { "type", 1, 0, 't' },
2019 static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc,
2022 struct mgmt_cp_disconnect cp;
2023 uint8_t type = BDADDR_BREDR;
2026 while ((opt = getopt_long(argc, argv, "+t:h", disconnect_options,
2030 type = strtol(optarg, NULL, 0);
2035 return noninteractive_quit(EXIT_SUCCESS);
2039 return noninteractive_quit(EXIT_FAILURE);
2049 return noninteractive_quit(EXIT_FAILURE);
2052 if (index == MGMT_INDEX_NONE)
2055 memset(&cp, 0, sizeof(cp));
2056 str2ba(argv[0], &cp.addr.bdaddr);
2057 cp.addr.type = type;
2059 if (mgmt_send(mgmt, MGMT_OP_DISCONNECT, index, sizeof(cp), &cp,
2060 disconnect_rsp, NULL, NULL) == 0) {
2061 error("Unable to send disconnect cmd");
2062 return noninteractive_quit(EXIT_FAILURE);
2066 static void con_rsp(uint8_t status, uint16_t len, const void *param,
2069 const struct mgmt_rp_get_connections *rp = param;
2072 if (len < sizeof(*rp)) {
2073 error("Too small (%u bytes) get_connections rsp", len);
2074 return noninteractive_quit(EXIT_FAILURE);
2077 count = get_le16(&rp->conn_count);
2078 if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) {
2079 error("Invalid get_connections length (count=%u, len=%u)",
2081 return noninteractive_quit(EXIT_FAILURE);
2084 for (i = 0; i < count; i++) {
2087 ba2str(&rp->addr[i].bdaddr, addr);
2089 print("%s type %s", addr, typestr(rp->addr[i].type));
2092 noninteractive_quit(EXIT_SUCCESS);
2095 static void cmd_con(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2097 if (index == MGMT_INDEX_NONE)
2100 if (mgmt_send(mgmt, MGMT_OP_GET_CONNECTIONS, index, 0, NULL,
2101 con_rsp, NULL, NULL) == 0) {
2102 error("Unable to send get_connections cmd");
2103 return noninteractive_quit(EXIT_FAILURE);
2107 static void find_service_rsp(uint8_t status, uint16_t len, const void *param,
2111 error("Start Service Discovery failed: status 0x%02x (%s)",
2112 status, mgmt_errstr(status));
2113 return noninteractive_quit(EXIT_FAILURE);
2116 print("Service discovery started");
2120 static void find_service_usage(void)
2122 print("Usage: find-service [-u UUID] [-r RSSI_Threshold] [-l|-b]");
2125 static struct option find_service_options[] = {
2126 { "help", no_argument, 0, 'h' },
2127 { "le-only", no_argument, 0, 'l' },
2128 { "bredr-only", no_argument, 0, 'b' },
2129 { "uuid", required_argument, 0, 'u' },
2130 { "rssi", required_argument, 0, 'r' },
2134 static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
2136 if (uuid->type == SDP_UUID16)
2137 sdp_uuid16_to_uuid128(uuid128, uuid);
2138 else if (uuid->type == SDP_UUID32)
2139 sdp_uuid32_to_uuid128(uuid128, uuid);
2141 memcpy(uuid128, uuid, sizeof(*uuid));
2146 static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
2149 struct mgmt_cp_start_service_discovery *cp;
2150 uint8_t buf[sizeof(*cp) + 16 * MAX_UUIDS];
2154 uint8_t type = SCAN_TYPE_DUAL;
2159 if (index == MGMT_INDEX_NONE)
2166 find_service_usage();
2167 return noninteractive_quit(EXIT_FAILURE);
2170 while ((opt = getopt_long(argc, argv, "+lbu:r:p:h",
2171 find_service_options, NULL)) != -1) {
2174 type &= ~SCAN_TYPE_BREDR;
2175 type |= SCAN_TYPE_LE;
2178 type |= SCAN_TYPE_BREDR;
2179 type &= ~SCAN_TYPE_LE;
2182 if (count == MAX_UUIDS) {
2183 print("Max %u UUIDs supported", MAX_UUIDS);
2185 return noninteractive_quit(EXIT_FAILURE);
2188 if (bt_string2uuid(&uuid, optarg) < 0) {
2189 print("Invalid UUID: %s", optarg);
2191 return noninteractive_quit(EXIT_FAILURE);
2194 uuid_to_uuid128(&uuid128, &uuid);
2195 ntoh128((uint128_t *) uuid128.value.uuid128.data,
2197 htob128(&uint128, (uint128_t *) cp->uuids[count++]);
2200 rssi = atoi(optarg);
2203 find_service_usage();
2205 return noninteractive_quit(EXIT_SUCCESS);
2207 find_service_usage();
2209 return noninteractive_quit(EXIT_FAILURE);
2218 find_service_usage();
2219 return noninteractive_quit(EXIT_FAILURE);
2225 cp->uuid_count = cpu_to_le16(count);
2227 if (mgmt_send(mgmt, MGMT_OP_START_SERVICE_DISCOVERY, index,
2228 sizeof(*cp) + count * 16, cp,
2229 find_service_rsp, NULL, NULL) == 0) {
2230 error("Unable to send start_service_discovery cmd");
2231 return noninteractive_quit(EXIT_FAILURE);
2235 static void find_rsp(uint8_t status, uint16_t len, const void *param,
2239 error("Unable to start discovery. status 0x%02x (%s)",
2240 status, mgmt_errstr(status));
2241 return noninteractive_quit(EXIT_FAILURE);
2244 print("Discovery started");
2248 static void find_usage(void)
2250 print("Usage: find [-l|-b]>");
2253 static struct option find_options[] = {
2254 { "help", 0, 0, 'h' },
2255 { "le-only", 1, 0, 'l' },
2256 { "bredr-only", 1, 0, 'b' },
2257 { "limited", 1, 0, 'L' },
2261 static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2263 struct mgmt_cp_start_discovery cp;
2264 uint8_t op = MGMT_OP_START_DISCOVERY;
2265 uint8_t type = SCAN_TYPE_DUAL;
2268 if (index == MGMT_INDEX_NONE)
2271 while ((opt = getopt_long(argc, argv, "+lbLh", find_options,
2275 type &= ~SCAN_TYPE_BREDR;
2276 type |= SCAN_TYPE_LE;
2279 type |= SCAN_TYPE_BREDR;
2280 type &= ~SCAN_TYPE_LE;
2283 op = MGMT_OP_START_LIMITED_DISCOVERY;
2288 return noninteractive_quit(EXIT_SUCCESS);
2292 return noninteractive_quit(EXIT_FAILURE);
2300 memset(&cp, 0, sizeof(cp));
2303 if (mgmt_send(mgmt, op, index, sizeof(cp), &cp, find_rsp,
2305 error("Unable to send start_discovery cmd");
2306 return noninteractive_quit(EXIT_FAILURE);
2310 static void stop_find_rsp(uint8_t status, uint16_t len, const void *param,
2315 "Stop Discovery failed: status 0x%02x (%s)\n",
2316 status, mgmt_errstr(status));
2317 return noninteractive_quit(EXIT_SUCCESS);
2320 printf("Discovery stopped\n");
2323 noninteractive_quit(EXIT_SUCCESS);
2326 static void stop_find_usage(void)
2328 printf("Usage: btmgmt stop-find [-l|-b]>\n");
2331 static struct option stop_find_options[] = {
2332 { "help", 0, 0, 'h' },
2333 { "le-only", 1, 0, 'l' },
2334 { "bredr-only", 1, 0, 'b' },
2338 static void cmd_stop_find(struct mgmt *mgmt, uint16_t index, int argc,
2341 struct mgmt_cp_stop_discovery cp;
2342 uint8_t type = SCAN_TYPE_DUAL;
2345 if (index == MGMT_INDEX_NONE)
2348 while ((opt = getopt_long(argc, argv, "+lbh", stop_find_options,
2352 type &= ~SCAN_TYPE_BREDR;
2353 type |= SCAN_TYPE_LE;
2356 type |= SCAN_TYPE_BREDR;
2357 type &= ~SCAN_TYPE_LE;
2371 memset(&cp, 0, sizeof(cp));
2374 if (mgmt_send(mgmt, MGMT_OP_STOP_DISCOVERY, index, sizeof(cp), &cp,
2375 stop_find_rsp, NULL, NULL) == 0) {
2376 fprintf(stderr, "Unable to send stop_discovery cmd\n");
2381 static void name_rsp(uint8_t status, uint16_t len, const void *param,
2385 error("Unable to set local name with status 0x%02x (%s)",
2386 status, mgmt_errstr(status));
2388 noninteractive_quit(EXIT_SUCCESS);
2391 static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2393 struct mgmt_cp_set_local_name cp;
2396 print("Usage: %s <name> [shortname]", argv[0]);
2397 return noninteractive_quit(EXIT_FAILURE);
2400 if (index == MGMT_INDEX_NONE)
2403 memset(&cp, 0, sizeof(cp));
2404 strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH);
2406 strncpy((char *) cp.short_name, argv[2],
2407 MGMT_MAX_SHORT_NAME_LENGTH);
2409 if (mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, index, sizeof(cp), &cp,
2410 name_rsp, NULL, NULL) == 0) {
2411 error("Unable to send set_name cmd");
2412 return noninteractive_quit(EXIT_FAILURE);
2416 static void pair_rsp(uint8_t status, uint16_t len, const void *param,
2419 const struct mgmt_rp_pair_device *rp = param;
2422 if (len == 0 && status != 0) {
2423 error("Pairing failed with status 0x%02x (%s)",
2424 status, mgmt_errstr(status));
2425 return noninteractive_quit(EXIT_FAILURE);
2428 if (len != sizeof(*rp)) {
2429 error("Unexpected pair_rsp len %u", len);
2430 return noninteractive_quit(EXIT_FAILURE);
2433 if (!memcmp(&rp->addr, &prompt.addr, sizeof(rp->addr)))
2436 ba2str(&rp->addr.bdaddr, addr);
2439 error("Pairing with %s (%s) failed. status 0x%02x (%s)",
2440 addr, typestr(rp->addr.type), status,
2441 mgmt_errstr(status));
2443 print("Paired with %s (%s)", addr, typestr(rp->addr.type));
2445 noninteractive_quit(EXIT_SUCCESS);
2448 static void pair_usage(void)
2450 print("Usage: pair [-c cap] [-t type] <remote address>");
2453 static struct option pair_options[] = {
2454 { "help", 0, 0, 'h' },
2455 { "capability", 1, 0, 'c' },
2456 { "type", 1, 0, 't' },
2460 static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2462 struct mgmt_cp_pair_device cp;
2464 uint8_t type = BDADDR_BREDR;
2468 while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options,
2472 cap = strtol(optarg, NULL, 0);
2475 type = strtol(optarg, NULL, 0);
2480 return noninteractive_quit(EXIT_SUCCESS);
2484 return noninteractive_quit(EXIT_FAILURE);
2494 return noninteractive_quit(EXIT_FAILURE);
2497 if (index == MGMT_INDEX_NONE)
2500 memset(&cp, 0, sizeof(cp));
2501 str2ba(argv[0], &cp.addr.bdaddr);
2502 cp.addr.type = type;
2505 ba2str(&cp.addr.bdaddr, addr);
2506 print("Pairing with %s (%s)", addr, typestr(cp.addr.type));
2508 if (mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp,
2509 pair_rsp, NULL, NULL) == 0) {
2510 error("Unable to send pair_device cmd");
2511 return noninteractive_quit(EXIT_FAILURE);
2515 static void cancel_pair_rsp(uint8_t status, uint16_t len, const void *param,
2518 const struct mgmt_addr_info *rp = param;
2521 if (len == 0 && status != 0) {
2522 error("Cancel Pairing failed with 0x%02x (%s)",
2523 status, mgmt_errstr(status));
2524 return noninteractive_quit(EXIT_FAILURE);
2527 if (len != sizeof(*rp)) {
2528 error("Unexpected cancel_pair_rsp len %u", len);
2529 return noninteractive_quit(EXIT_FAILURE);
2532 ba2str(&rp->bdaddr, addr);
2535 error("Cancel Pairing with %s (%s) failed. 0x%02x (%s)",
2536 addr, typestr(rp->type), status,
2537 mgmt_errstr(status));
2539 print("Pairing Cancelled with %s", addr);
2541 noninteractive_quit(EXIT_SUCCESS);
2544 static void cancel_pair_usage(void)
2546 print("Usage: cancelpair [-t type] <remote address>");
2549 static struct option cancel_pair_options[] = {
2550 { "help", 0, 0, 'h' },
2551 { "type", 1, 0, 't' },
2555 static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc,
2558 struct mgmt_addr_info cp;
2559 uint8_t type = BDADDR_BREDR;
2562 while ((opt = getopt_long(argc, argv, "+t:h", cancel_pair_options,
2566 type = strtol(optarg, NULL, 0);
2569 cancel_pair_usage();
2571 return noninteractive_quit(EXIT_SUCCESS);
2573 cancel_pair_usage();
2575 return noninteractive_quit(EXIT_FAILURE);
2584 cancel_pair_usage();
2585 return noninteractive_quit(EXIT_FAILURE);
2588 if (index == MGMT_INDEX_NONE)
2591 memset(&cp, 0, sizeof(cp));
2592 str2ba(argv[0], &cp.bdaddr);
2595 if (mgmt_send(mgmt, MGMT_OP_CANCEL_PAIR_DEVICE, index, sizeof(cp), &cp,
2596 cancel_pair_rsp, NULL, NULL) == 0) {
2597 error("Unable to send cancel_pair_device cmd");
2598 return noninteractive_quit(EXIT_FAILURE);
2602 static void unpair_rsp(uint8_t status, uint16_t len, const void *param,
2605 const struct mgmt_rp_unpair_device *rp = param;
2608 if (len == 0 && status != 0) {
2609 error("Unpair device failed. status 0x%02x (%s)",
2610 status, mgmt_errstr(status));
2611 return noninteractive_quit(EXIT_FAILURE);
2614 if (len != sizeof(*rp)) {
2615 error("Unexpected unpair_device_rsp len %u", len);
2616 return noninteractive_quit(EXIT_FAILURE);
2619 ba2str(&rp->addr.bdaddr, addr);
2622 error("Unpairing %s failed. status 0x%02x (%s)",
2623 addr, status, mgmt_errstr(status));
2625 print("%s unpaired", addr);
2627 noninteractive_quit(EXIT_SUCCESS);
2630 static void unpair_usage(void)
2632 print("Usage: unpair [-t type] <remote address>");
2635 static struct option unpair_options[] = {
2636 { "help", 0, 0, 'h' },
2637 { "type", 1, 0, 't' },
2641 static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc,
2644 struct mgmt_cp_unpair_device cp;
2645 uint8_t type = BDADDR_BREDR;
2648 while ((opt = getopt_long(argc, argv, "+t:h", unpair_options,
2652 type = strtol(optarg, NULL, 0);
2657 return noninteractive_quit(EXIT_SUCCESS);
2661 return noninteractive_quit(EXIT_FAILURE);
2671 return noninteractive_quit(EXIT_FAILURE);
2674 if (index == MGMT_INDEX_NONE)
2677 memset(&cp, 0, sizeof(cp));
2678 str2ba(argv[0], &cp.addr.bdaddr);
2679 cp.addr.type = type;
2682 if (mgmt_send(mgmt, MGMT_OP_UNPAIR_DEVICE, index, sizeof(cp), &cp,
2683 unpair_rsp, NULL, NULL) == 0) {
2684 error("Unable to send unpair_device cmd");
2685 return noninteractive_quit(EXIT_FAILURE);
2689 static void keys_rsp(uint8_t status, uint16_t len, const void *param,
2693 error("Load keys failed with status 0x%02x (%s)",
2694 status, mgmt_errstr(status));
2696 print("Keys successfully loaded");
2698 noninteractive_quit(EXIT_SUCCESS);
2701 static void cmd_keys(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2703 struct mgmt_cp_load_link_keys cp;
2705 if (index == MGMT_INDEX_NONE)
2708 memset(&cp, 0, sizeof(cp));
2710 if (mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index, sizeof(cp), &cp,
2711 keys_rsp, NULL, NULL) == 0) {
2712 error("Unable to send load_keys cmd");
2713 return noninteractive_quit(EXIT_FAILURE);
2717 static void ltks_rsp(uint8_t status, uint16_t len, const void *param,
2721 error("Load keys failed with status 0x%02x (%s)",
2722 status, mgmt_errstr(status));
2724 print("Long term keys successfully loaded");
2726 noninteractive_quit(EXIT_SUCCESS);
2729 static void cmd_ltks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2731 struct mgmt_cp_load_long_term_keys cp;
2733 if (index == MGMT_INDEX_NONE)
2736 memset(&cp, 0, sizeof(cp));
2738 if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index, sizeof(cp), &cp,
2739 ltks_rsp, NULL, NULL) == 0) {
2740 error("Unable to send load_ltks cmd");
2741 return noninteractive_quit(EXIT_SUCCESS);
2745 static void irks_rsp(uint8_t status, uint16_t len, const void *param,
2749 error("Load IRKs failed with status 0x%02x (%s)",
2750 status, mgmt_errstr(status));
2752 print("Identity Resolving Keys successfully loaded");
2754 noninteractive_quit(EXIT_SUCCESS);
2757 static void irks_usage(void)
2759 print("Usage: irks [--local]");
2762 static struct option irks_options[] = {
2763 { "help", 0, 0, 'h' },
2764 { "local", 1, 0, 'l' },
2770 static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2772 struct mgmt_cp_load_irks *cp;
2773 uint8_t buf[sizeof(*cp) + 23 * MAX_IRKS];
2774 uint16_t count, local_index;
2777 if (index == MGMT_INDEX_NONE)
2783 while ((opt = getopt_long(argc, argv, "+l:h",
2784 irks_options, NULL)) != -1) {
2787 if (count >= MAX_IRKS) {
2788 error("Number of IRKs exceeded");
2790 return noninteractive_quit(EXIT_FAILURE);
2792 if (strlen(optarg) > 3 &&
2793 strncasecmp(optarg, "hci", 3) == 0)
2794 local_index = atoi(optarg + 3);
2796 local_index = atoi(optarg);
2797 if (!load_identity(local_index, &cp->irks[count])) {
2798 error("Unable to load identity");
2800 return noninteractive_quit(EXIT_FAILURE);
2807 return noninteractive_quit(EXIT_SUCCESS);
2811 return noninteractive_quit(EXIT_FAILURE);
2821 return noninteractive_quit(EXIT_FAILURE);
2824 cp->irk_count = cpu_to_le16(count);
2826 if (mgmt_send(mgmt, MGMT_OP_LOAD_IRKS, index,
2827 sizeof(*cp) + count * 23, cp,
2828 irks_rsp, NULL, NULL) == 0) {
2829 error("Unable to send load_irks cmd");
2830 return noninteractive_quit(EXIT_FAILURE);
2834 static void block_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
2837 const struct mgmt_addr_info *rp = param;
2840 if (len == 0 && status != 0) {
2841 error("%s failed, status 0x%02x (%s)",
2842 mgmt_opstr(op), status, mgmt_errstr(status));
2843 return noninteractive_quit(EXIT_FAILURE);
2846 if (len != sizeof(*rp)) {
2847 error("Unexpected %s len %u", mgmt_opstr(op), len);
2848 return noninteractive_quit(EXIT_FAILURE);
2851 ba2str(&rp->bdaddr, addr);
2854 error("%s %s (%s) failed. status 0x%02x (%s)",
2855 mgmt_opstr(op), addr, typestr(rp->type),
2856 status, mgmt_errstr(status));
2858 print("%s %s succeeded", mgmt_opstr(op), addr);
2860 noninteractive_quit(EXIT_SUCCESS);
2863 static void block_usage(void)
2865 print("Usage: block [-t type] <remote address>");
2868 static struct option block_options[] = {
2869 { "help", 0, 0, 'h' },
2870 { "type", 1, 0, 't' },
2874 static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2876 struct mgmt_cp_block_device cp;
2877 uint8_t type = BDADDR_BREDR;
2880 while ((opt = getopt_long(argc, argv, "+t:h", block_options,
2884 type = strtol(optarg, NULL, 0);
2889 return noninteractive_quit(EXIT_SUCCESS);
2893 return noninteractive_quit(EXIT_FAILURE);
2903 return noninteractive_quit(EXIT_FAILURE);
2906 if (index == MGMT_INDEX_NONE)
2909 memset(&cp, 0, sizeof(cp));
2910 str2ba(argv[0], &cp.addr.bdaddr);
2911 cp.addr.type = type;
2913 if (send_cmd(mgmt, MGMT_OP_BLOCK_DEVICE, index, sizeof(cp), &cp,
2915 error("Unable to send block_device cmd");
2916 return noninteractive_quit(EXIT_FAILURE);
2920 static void unblock_usage(void)
2922 print("Usage: unblock [-t type] <remote address>");
2925 static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
2928 struct mgmt_cp_unblock_device cp;
2929 uint8_t type = BDADDR_BREDR;
2932 while ((opt = getopt_long(argc, argv, "+t:h", block_options,
2936 type = strtol(optarg, NULL, 0);
2941 return noninteractive_quit(EXIT_SUCCESS);
2945 return noninteractive_quit(EXIT_FAILURE);
2955 return noninteractive_quit(EXIT_FAILURE);
2958 if (index == MGMT_INDEX_NONE)
2961 memset(&cp, 0, sizeof(cp));
2962 str2ba(argv[0], &cp.addr.bdaddr);
2963 cp.addr.type = type;
2965 if (send_cmd(mgmt, MGMT_OP_UNBLOCK_DEVICE, index, sizeof(cp), &cp,
2967 error("Unable to send unblock_device cmd");
2968 return noninteractive_quit(EXIT_FAILURE);
2972 static void cmd_add_uuid(struct mgmt *mgmt, uint16_t index, int argc,
2975 struct mgmt_cp_add_uuid cp;
2977 uuid_t uuid, uuid128;
2980 print("UUID and service hint needed");
2981 return noninteractive_quit(EXIT_FAILURE);
2984 if (index == MGMT_INDEX_NONE)
2987 if (bt_string2uuid(&uuid, argv[1]) < 0) {
2988 print("Invalid UUID: %s", argv[1]);
2989 return noninteractive_quit(EXIT_FAILURE);
2992 memset(&cp, 0, sizeof(cp));
2994 uuid_to_uuid128(&uuid128, &uuid);
2995 ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
2996 htob128(&uint128, (uint128_t *) cp.uuid);
2998 cp.svc_hint = atoi(argv[2]);
3000 if (send_cmd(mgmt, MGMT_OP_ADD_UUID, index, sizeof(cp), &cp,
3002 error("Unable to send add_uuid cmd");
3003 return noninteractive_quit(EXIT_FAILURE);
3007 static void cmd_remove_uuid(struct mgmt *mgmt, uint16_t index, int argc,
3010 struct mgmt_cp_remove_uuid cp;
3012 uuid_t uuid, uuid128;
3015 print("UUID needed");
3016 return noninteractive_quit(EXIT_FAILURE);
3019 if (index == MGMT_INDEX_NONE)
3022 if (bt_string2uuid(&uuid, argv[1]) < 0) {
3023 print("Invalid UUID: %s", argv[1]);
3024 return noninteractive_quit(EXIT_FAILURE);
3027 memset(&cp, 0, sizeof(cp));
3029 uuid_to_uuid128(&uuid128, &uuid);
3030 ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
3031 htob128(&uint128, (uint128_t *) cp.uuid);
3033 if (send_cmd(mgmt, MGMT_OP_REMOVE_UUID, index, sizeof(cp), &cp,
3035 error("Unable to send remove_uuid cmd");
3036 return noninteractive_quit(EXIT_FAILURE);
3040 static void cmd_clr_uuids(struct mgmt *mgmt, uint16_t index, int argc,
3043 char *uuid_any = "00000000-0000-0000-0000-000000000000";
3044 char *rm_argv[] = { "rm-uuid", uuid_any, NULL };
3046 cmd_remove_uuid(mgmt, index, 2, rm_argv);
3049 static void local_oob_rsp(uint8_t status, uint16_t len, const void *param,
3052 const struct mgmt_rp_read_local_oob_data *rp = param;
3056 error("Read Local OOB Data failed with status 0x%02x (%s)",
3057 status, mgmt_errstr(status));
3058 return noninteractive_quit(EXIT_FAILURE);
3061 if (len < sizeof(*rp)) {
3062 error("Too small (%u bytes) read_local_oob rsp", len);
3063 return noninteractive_quit(EXIT_FAILURE);
3066 bin2hex(rp->hash192, 16, str, sizeof(str));
3067 print("Hash C from P-192: %s", str);
3069 bin2hex(rp->rand192, 16, str, sizeof(str));
3070 print("Randomizer R with P-192: %s", str);
3072 if (len < sizeof(*rp))
3073 return noninteractive_quit(EXIT_SUCCESS);
3075 bin2hex(rp->hash256, 16, str, sizeof(str));
3076 print("Hash C from P-256: %s", str);
3078 bin2hex(rp->rand256, 16, str, sizeof(str));
3079 print("Randomizer R with P-256: %s", str);
3081 noninteractive_quit(EXIT_SUCCESS);
3084 static void cmd_local_oob(struct mgmt *mgmt, uint16_t index,
3085 int argc, char **argv)
3087 if (index == MGMT_INDEX_NONE)
3090 if (mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL,
3091 local_oob_rsp, NULL, NULL) == 0) {
3092 error("Unable to send read_local_oob cmd");
3093 return noninteractive_quit(EXIT_FAILURE);
3097 static void remote_oob_rsp(uint8_t status, uint16_t len, const void *param,
3100 const struct mgmt_addr_info *rp = param;
3104 error("Add Remote OOB Data failed: 0x%02x (%s)",
3105 status, mgmt_errstr(status));
3109 if (len < sizeof(*rp)) {
3110 error("Too small (%u bytes) add_remote_oob rsp", len);
3114 ba2str(&rp->bdaddr, addr);
3115 print("Remote OOB data added for %s (%u)", addr, rp->type);
3118 static void remote_oob_usage(void)
3120 print("Usage: remote-oob [-t <addr_type>] "
3121 "[-r <rand192>] [-h <hash192>] [-R <rand256>] [-H <hash256>] "
3125 static struct option remote_oob_opt[] = {
3126 { "help", 0, 0, 'h' },
3127 { "type", 1, 0, 't' },
3131 static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index,
3132 int argc, char **argv)
3134 struct mgmt_cp_add_remote_oob_data cp;
3137 memset(&cp, 0, sizeof(cp));
3138 cp.addr.type = BDADDR_BREDR;
3140 while ((opt = getopt_long(argc, argv, "+t:r:R:h:H:",
3141 remote_oob_opt, NULL)) != -1) {
3144 cp.addr.type = strtol(optarg, NULL, 0);
3147 hex2bin(optarg, cp.rand192, 16);
3150 hex2bin(optarg, cp.hash192, 16);
3153 hex2bin(optarg, cp.rand256, 16);
3156 hex2bin(optarg, cp.hash256, 16);
3160 return noninteractive_quit(EXIT_FAILURE);
3170 return noninteractive_quit(EXIT_FAILURE);
3173 if (index == MGMT_INDEX_NONE)
3176 str2ba(argv[0], &cp.addr.bdaddr);
3178 print("Adding OOB data for %s (%s)", argv[0], typestr(cp.addr.type));
3180 if (mgmt_send(mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA, index,
3181 sizeof(cp), &cp, remote_oob_rsp,
3183 error("Unable to send add_remote_oob cmd");
3184 return noninteractive_quit(EXIT_FAILURE);
3188 static void did_rsp(uint8_t status, uint16_t len, const void *param,
3192 error("Set Device ID failed with status 0x%02x (%s)",
3193 status, mgmt_errstr(status));
3195 print("Device ID successfully set");
3197 noninteractive_quit(EXIT_SUCCESS);
3200 static void did_usage(void)
3202 print("Usage: did <source>:<vendor>:<product>:<version>");
3203 print(" possible source values: bluetooth, usb");
3206 static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
3208 struct mgmt_cp_set_device_id cp;
3209 uint16_t vendor, product, version , source;
3214 return noninteractive_quit(EXIT_FAILURE);
3217 result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product,
3224 result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product,
3232 return noninteractive_quit(EXIT_FAILURE);
3235 if (index == MGMT_INDEX_NONE)
3238 cp.source = htobs(source);
3239 cp.vendor = htobs(vendor);
3240 cp.product = htobs(product);
3241 cp.version = htobs(version);
3243 if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_ID, index, sizeof(cp), &cp,
3244 did_rsp, NULL, NULL) == 0) {
3245 error("Unable to send set_device_id cmd");
3246 return noninteractive_quit(EXIT_FAILURE);
3250 static void static_addr_rsp(uint8_t status, uint16_t len, const void *param,
3254 error("Set static address failed with status 0x%02x (%s)",
3255 status, mgmt_errstr(status));
3257 print("Static address successfully set");
3259 noninteractive_quit(EXIT_SUCCESS);
3262 static void static_addr_usage(void)
3264 print("Usage: static-addr <address>");
3267 static void cmd_static_addr(struct mgmt *mgmt, uint16_t index,
3268 int argc, char **argv)
3270 struct mgmt_cp_set_static_address cp;
3273 static_addr_usage();
3274 return noninteractive_quit(EXIT_FAILURE);
3277 if (index == MGMT_INDEX_NONE)
3280 str2ba(argv[1], &cp.bdaddr);
3282 if (mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, sizeof(cp), &cp,
3283 static_addr_rsp, NULL, NULL) == 0) {
3284 error("Unable to send set_static_address cmd");
3285 return noninteractive_quit(EXIT_FAILURE);
3289 static void options_rsp(uint16_t op, uint16_t id, uint8_t status,
3290 uint16_t len, const void *param)
3292 const uint32_t *rp = param;
3295 error("%s for hci%u failed with status 0x%02x (%s)",
3296 mgmt_opstr(op), id, status, mgmt_errstr(status));
3297 return noninteractive_quit(EXIT_FAILURE);
3300 if (len < sizeof(*rp)) {
3301 error("Too small %s response (%u bytes)",
3302 mgmt_opstr(op), len);
3303 return noninteractive_quit(EXIT_FAILURE);
3306 print("hci%u %s complete, options: %s", id, mgmt_opstr(op),
3307 options2str(get_le32(rp)));
3309 noninteractive_quit(EXIT_SUCCESS);
3312 static void cmd_public_addr(struct mgmt *mgmt, uint16_t index,
3313 int argc, char **argv)
3315 struct mgmt_cp_set_public_address cp;
3318 print("Usage: public-addr <address>");
3319 return noninteractive_quit(EXIT_FAILURE);
3322 if (index == MGMT_INDEX_NONE)
3325 str2ba(argv[1], &cp.bdaddr);
3327 if (send_cmd(mgmt, MGMT_OP_SET_PUBLIC_ADDRESS, index, sizeof(cp), &cp,
3328 options_rsp) == 0) {
3329 error("Unable to send Set Public Address cmd");
3330 return noninteractive_quit(EXIT_FAILURE);
3334 static void cmd_ext_config(struct mgmt *mgmt, uint16_t index,
3335 int argc, char **argv)
3337 struct mgmt_cp_set_external_config cp;
3340 print("Specify \"on\" or \"off\"");
3341 return noninteractive_quit(EXIT_FAILURE);
3344 if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
3346 else if (strcasecmp(argv[1], "off") == 0)
3349 cp.config = atoi(argv[1]);
3351 if (index == MGMT_INDEX_NONE)
3354 if (send_cmd(mgmt, MGMT_OP_SET_EXTERNAL_CONFIG, index, sizeof(cp), &cp,
3355 options_rsp) == 0) {
3356 error("Unable to send Set External Config cmd");
3357 return noninteractive_quit(EXIT_FAILURE);
3361 static void cmd_debug_keys(struct mgmt *mgmt, uint16_t index,
3362 int argc, char **argv)
3364 cmd_setting(mgmt, index, MGMT_OP_SET_DEBUG_KEYS, argc, argv);
3367 static void conn_info_rsp(uint8_t status, uint16_t len, const void *param,
3370 const struct mgmt_rp_get_conn_info *rp = param; char addr[18];
3372 if (len == 0 && status != 0) {
3373 error("Get Conn Info failed, status 0x%02x (%s)",
3374 status, mgmt_errstr(status));
3375 return noninteractive_quit(EXIT_FAILURE);
3378 if (len < sizeof(*rp)) {
3379 error("Unexpected Get Conn Info len %u", len);
3380 return noninteractive_quit(EXIT_FAILURE);
3383 ba2str(&rp->addr.bdaddr, addr);
3386 error("Get Conn Info for %s (%s) failed. status 0x%02x (%s)",
3387 addr, typestr(rp->addr.type),
3388 status, mgmt_errstr(status));
3390 print("Connection Information for %s (%s)",
3391 addr, typestr(rp->addr.type));
3392 print("\tRSSI %d\tTX power %d\tmaximum TX power %d",
3393 rp->rssi, rp->tx_power, rp->max_tx_power);
3396 noninteractive_quit(EXIT_SUCCESS);
3399 static void conn_info_usage(void)
3401 print("Usage: conn-info [-t type] <remote address>");
3404 static struct option conn_info_options[] = {
3405 { "help", 0, 0, 'h' },
3406 { "type", 1, 0, 't' },
3410 static void cmd_conn_info(struct mgmt *mgmt, uint16_t index,
3411 int argc, char **argv)
3413 struct mgmt_cp_get_conn_info cp;
3414 uint8_t type = BDADDR_BREDR;
3417 while ((opt = getopt_long(argc, argv, "+t:h", conn_info_options,
3421 type = strtol(optarg, NULL, 0);
3425 return noninteractive_quit(EXIT_SUCCESS);
3428 return noninteractive_quit(EXIT_FAILURE);
3438 return noninteractive_quit(EXIT_FAILURE);
3441 if (index == MGMT_INDEX_NONE)
3444 memset(&cp, 0, sizeof(cp));
3445 str2ba(argv[0], &cp.addr.bdaddr);
3446 cp.addr.type = type;
3448 if (mgmt_send(mgmt, MGMT_OP_GET_CONN_INFO, index, sizeof(cp), &cp,
3449 conn_info_rsp, NULL, NULL) == 0) {
3450 error("Unable to send get_conn_info cmd");
3451 return noninteractive_quit(EXIT_FAILURE);
3455 static void io_cap_rsp(uint8_t status, uint16_t len, const void *param,
3459 error("Could not set IO Capability with status 0x%02x (%s)",
3460 status, mgmt_errstr(status));
3462 print("IO Capabilities successfully set");
3464 noninteractive_quit(EXIT_SUCCESS);
3467 static void io_cap_usage(void)
3469 print("Usage: io-cap <cap>");
3472 static void cmd_io_cap(struct mgmt *mgmt, uint16_t index,
3473 int argc, char **argv)
3475 struct mgmt_cp_set_io_capability cp;
3480 return noninteractive_quit(EXIT_FAILURE);
3483 if (index == MGMT_INDEX_NONE)
3486 cap = strtol(argv[1], NULL, 0);
3487 memset(&cp, 0, sizeof(cp));
3488 cp.io_capability = cap;
3490 if (mgmt_send(mgmt, MGMT_OP_SET_IO_CAPABILITY, index, sizeof(cp), &cp,
3491 io_cap_rsp, NULL, NULL) == 0) {
3492 error("Unable to send set-io-cap cmd");
3493 return noninteractive_quit(EXIT_FAILURE);
3497 static void scan_params_rsp(uint8_t status, uint16_t len, const void *param,
3501 error("Set scan parameters failed with status 0x%02x (%s)",
3502 status, mgmt_errstr(status));
3504 print("Scan parameters successfully set");
3506 noninteractive_quit(EXIT_SUCCESS);
3509 static void scan_params_usage(void)
3511 print("Usage: scan-params <interval> <window>");
3514 static void cmd_scan_params(struct mgmt *mgmt, uint16_t index,
3515 int argc, char **argv)
3517 struct mgmt_cp_set_scan_params cp;
3520 scan_params_usage();
3521 return noninteractive_quit(EXIT_FAILURE);
3524 if (index == MGMT_INDEX_NONE)
3527 cp.interval = strtol(argv[1], NULL, 0);
3528 cp.window = strtol(argv[2], NULL, 0);
3530 if (mgmt_send(mgmt, MGMT_OP_SET_SCAN_PARAMS, index, sizeof(cp), &cp,
3531 scan_params_rsp, NULL, NULL) == 0) {
3532 error("Unable to send set_scan_params cmd");
3533 return noninteractive_quit(EXIT_FAILURE);
3537 static void clock_info_rsp(uint8_t status, uint16_t len, const void *param,
3540 const struct mgmt_rp_get_clock_info *rp = param;
3542 if (len < sizeof(*rp)) {
3543 error("Unexpected Get Clock Info len %u", len);
3544 return noninteractive_quit(EXIT_FAILURE);
3548 error("Get Clock Info failed with status 0x%02x (%s)",
3549 status, mgmt_errstr(status));
3550 return noninteractive_quit(EXIT_FAILURE);
3553 print("Local Clock: %u", le32_to_cpu(rp->local_clock));
3554 print("Piconet Clock: %u", le32_to_cpu(rp->piconet_clock));
3555 print("Accurary: %u", le16_to_cpu(rp->accuracy));
3557 noninteractive_quit(EXIT_SUCCESS);
3560 static void cmd_clock_info(struct mgmt *mgmt, uint16_t index,
3561 int argc, char **argv)
3563 struct mgmt_cp_get_clock_info cp;
3565 if (index == MGMT_INDEX_NONE)
3568 memset(&cp, 0, sizeof(cp));
3571 str2ba(argv[1], &cp.addr.bdaddr);
3573 if (mgmt_send(mgmt, MGMT_OP_GET_CLOCK_INFO, index, sizeof(cp), &cp,
3574 clock_info_rsp, NULL, NULL) == 0) {
3575 error("Unable to send get_clock_info cmd");
3576 return noninteractive_quit(EXIT_FAILURE);
3580 static void add_device_rsp(uint8_t status, uint16_t len, const void *param,
3584 error("Add device failed with status 0x%02x (%s)",
3585 status, mgmt_errstr(status));
3586 noninteractive_quit(EXIT_SUCCESS);
3589 static void add_device_usage(void)
3591 print("Usage: add-device [-a action] [-t type] <address>");
3594 static struct option add_device_options[] = {
3595 { "help", 0, 0, 'h' },
3596 { "action", 1, 0, 'a' },
3597 { "type", 1, 0, 't' },
3601 static void cmd_add_device(struct mgmt *mgmt, uint16_t index,
3602 int argc, char **argv)
3604 struct mgmt_cp_add_device cp;
3605 uint8_t action = 0x00;
3606 uint8_t type = BDADDR_BREDR;
3610 while ((opt = getopt_long(argc, argv, "+a:t:h", add_device_options,
3614 action = strtol(optarg, NULL, 0);
3617 type = strtol(optarg, NULL, 0);
3621 return noninteractive_quit(EXIT_SUCCESS);
3624 return noninteractive_quit(EXIT_FAILURE);
3634 return noninteractive_quit(EXIT_FAILURE);
3637 if (index == MGMT_INDEX_NONE)
3640 memset(&cp, 0, sizeof(cp));
3641 str2ba(argv[0], &cp.addr.bdaddr);
3642 cp.addr.type = type;
3645 ba2str(&cp.addr.bdaddr, addr);
3646 print("Adding device with %s (%s)", addr, typestr(cp.addr.type));
3648 if (mgmt_send(mgmt, MGMT_OP_ADD_DEVICE, index, sizeof(cp), &cp,
3649 add_device_rsp, NULL, NULL) == 0) {
3650 error("Unable to send add device command");
3651 return noninteractive_quit(EXIT_FAILURE);
3655 static void remove_device_rsp(uint8_t status, uint16_t len, const void *param,
3659 error("Remove device failed with status 0x%02x (%s)",
3660 status, mgmt_errstr(status));
3661 noninteractive_quit(EXIT_SUCCESS);
3664 static void del_device_usage(void)
3666 print("Usage: del-device [-t type] <address>");
3669 static struct option del_device_options[] = {
3670 { "help", 0, 0, 'h' },
3671 { "type", 1, 0, 't' },
3675 static void cmd_del_device(struct mgmt *mgmt, uint16_t index,
3676 int argc, char **argv)
3678 struct mgmt_cp_remove_device cp;
3679 uint8_t type = BDADDR_BREDR;
3683 while ((opt = getopt_long(argc, argv, "+t:h", del_device_options,
3687 type = strtol(optarg, NULL, 0);
3691 return noninteractive_quit(EXIT_SUCCESS);
3694 return noninteractive_quit(EXIT_FAILURE);
3704 return noninteractive_quit(EXIT_FAILURE);
3707 if (index == MGMT_INDEX_NONE)
3710 memset(&cp, 0, sizeof(cp));
3711 str2ba(argv[0], &cp.addr.bdaddr);
3712 cp.addr.type = type;
3714 ba2str(&cp.addr.bdaddr, addr);
3715 print("Removing device with %s (%s)", addr, typestr(cp.addr.type));
3717 if (mgmt_send(mgmt, MGMT_OP_REMOVE_DEVICE, index, sizeof(cp), &cp,
3718 remove_device_rsp, NULL, NULL) == 0) {
3719 error("Unable to send remove device command");
3720 return noninteractive_quit(EXIT_FAILURE);
3724 static void cmd_clr_devices(struct mgmt *mgmt, uint16_t index,
3725 int argc, char **argv)
3727 char *bdaddr_any = "00:00:00:00:00:00";
3728 char *rm_argv[] = { "del-device", bdaddr_any, NULL };
3730 cmd_del_device(mgmt, index, 2, rm_argv);
3733 static void local_oob_ext_rsp(uint8_t status, uint16_t len, const void *param,
3736 const struct mgmt_rp_read_local_oob_ext_data *rp = param;
3740 error("Read Local OOB Ext Data failed with status 0x%02x (%s)",
3741 status, mgmt_errstr(status));
3742 return noninteractive_quit(EXIT_FAILURE);
3745 if (len < sizeof(*rp)) {
3746 error("Too small (%u bytes) read_local_oob_ext rsp", len);
3747 return noninteractive_quit(EXIT_FAILURE);
3750 eir_len = le16_to_cpu(rp->eir_len);
3751 if (len != sizeof(*rp) + eir_len) {
3752 error("local_oob_ext: expected %zu bytes, got %u bytes",
3753 sizeof(*rp) + eir_len, len);
3754 return noninteractive_quit(EXIT_FAILURE);
3757 print_eir(rp->eir, eir_len);
3759 noninteractive_quit(EXIT_SUCCESS);
3762 static void cmd_bredr_oob(struct mgmt *mgmt, uint16_t index,
3763 int argc, char **argv)
3765 struct mgmt_cp_read_local_oob_ext_data cp;
3767 if (index == MGMT_INDEX_NONE)
3770 cp.type = SCAN_TYPE_BREDR;
3772 if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
3773 index, sizeof(cp), &cp,
3774 local_oob_ext_rsp, NULL, NULL)) {
3775 error("Unable to send read_local_oob_ext cmd");
3776 return noninteractive_quit(EXIT_FAILURE);
3780 static void cmd_le_oob(struct mgmt *mgmt, uint16_t index,
3781 int argc, char **argv)
3783 struct mgmt_cp_read_local_oob_ext_data cp;
3785 if (index == MGMT_INDEX_NONE)
3788 cp.type = SCAN_TYPE_LE;
3790 if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
3791 index, sizeof(cp), &cp,
3792 local_oob_ext_rsp, NULL, NULL)) {
3793 error("Unable to send read_local_oob_ext cmd");
3794 return noninteractive_quit(EXIT_FAILURE);
3798 static const char *adv_flags_str[] = {
3800 "general-discoverable",
3801 "limited-discoverable",
3804 "scan-rsp-appearance",
3805 "scan-rsp-local-name",
3808 static const char *adv_flags2str(uint32_t flags)
3810 static char str[256];
3817 for (i = 0; i < NELEM(adv_flags_str); i++) {
3818 if ((flags & (1 << i)) != 0)
3819 off += snprintf(str + off, sizeof(str) - off, "%s ",
3826 static void adv_features_rsp(uint8_t status, uint16_t len, const void *param,
3829 const struct mgmt_rp_read_adv_features *rp = param;
3830 uint32_t supported_flags;
3833 error("Reading adv features failed with status 0x%02x (%s)",
3834 status, mgmt_errstr(status));
3835 return noninteractive_quit(EXIT_FAILURE);
3838 if (len < sizeof(*rp)) {
3839 error("Too small adv features reply (%u bytes)", len);
3840 return noninteractive_quit(EXIT_FAILURE);
3843 if (len < sizeof(*rp) + rp->num_instances * sizeof(uint8_t)) {
3844 error("Instances count (%u) doesn't match reply length (%u)",
3845 rp->num_instances, len);
3846 return noninteractive_quit(EXIT_FAILURE);
3849 supported_flags = le32_to_cpu(rp->supported_flags);
3850 print("Supported flags: %s", adv_flags2str(supported_flags));
3851 print("Max advertising data len: %u", rp->max_adv_data_len);
3852 print("Max scan response data len: %u", rp->max_scan_rsp_len);
3853 print("Max instances: %u", rp->max_instances);
3855 print("Instances list with %u item%s", rp->num_instances,
3856 rp->num_instances != 1 ? "s" : "");
3858 return noninteractive_quit(EXIT_SUCCESS);
3861 static void cmd_advinfo(struct mgmt *mgmt, uint16_t index,
3862 int argc, char **argv)
3864 if (index == MGMT_INDEX_NONE)
3867 if (!mgmt_send(mgmt, MGMT_OP_READ_ADV_FEATURES, index, 0, NULL,
3868 adv_features_rsp, NULL, NULL)) {
3869 error("Unable to send advertising features command");
3870 return noninteractive_quit(EXIT_FAILURE);
3874 static void adv_size_info_rsp(uint8_t status, uint16_t len, const void *param,
3877 const struct mgmt_rp_get_adv_size_info *rp = param;
3881 error("Reading adv size info failed with status 0x%02x (%s)",
3882 status, mgmt_errstr(status));
3883 return noninteractive_quit(EXIT_FAILURE);
3886 if (len < sizeof(*rp)) {
3887 error("Too small adv size info reply (%u bytes)", len);
3888 return noninteractive_quit(EXIT_FAILURE);
3891 flags = le32_to_cpu(rp->flags);
3892 print("Instance: %u", rp->instance);
3893 print("Flags: %s", adv_flags2str(flags));
3894 print("Max advertising data len: %u", rp->max_adv_data_len);
3895 print("Max scan response data len: %u", rp->max_scan_rsp_len);
3897 return noninteractive_quit(EXIT_SUCCESS);
3900 static void advsize_usage(void)
3902 print("Usage: advsize [options] <instance_id>\nOptions:\n"
3903 "\t -c, --connectable \"connectable\" flag\n"
3904 "\t -g, --general-discov \"general-discoverable\" flag\n"
3905 "\t -l, --limited-discov \"limited-discoverable\" flag\n"
3906 "\t -m, --managed-flags \"managed-flags\" flag\n"
3907 "\t -p, --tx-power \"tx-power\" flag");
3910 static struct option advsize_options[] = {
3911 { "help", 0, 0, 'h' },
3912 { "connectable", 0, 0, 'c' },
3913 { "general-discov", 0, 0, 'g' },
3914 { "limited-discov", 0, 0, 'l' },
3915 { "managed-flags", 0, 0, 'm' },
3916 { "tx-power", 0, 0, 'p' },
3920 static void cmd_advsize(struct mgmt *mgmt, uint16_t index,
3921 int argc, char **argv)
3923 struct mgmt_cp_get_adv_size_info cp;
3928 while ((opt = getopt_long(argc, argv, "+cglmph",
3929 advsize_options, NULL)) != -1) {
3932 flags |= MGMT_ADV_FLAG_CONNECTABLE;
3935 flags |= MGMT_ADV_FLAG_DISCOV;
3938 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
3941 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
3944 flags |= MGMT_ADV_FLAG_TX_POWER;
3948 return noninteractive_quit(EXIT_FAILURE);
3958 return noninteractive_quit(EXIT_FAILURE);
3961 instance = strtol(argv[0], NULL, 0);
3963 if (index == MGMT_INDEX_NONE)
3966 memset(&cp, 0, sizeof(cp));
3968 cp.instance = instance;
3969 cp.flags = cpu_to_le32(flags);
3971 if (!mgmt_send(mgmt, MGMT_OP_GET_ADV_SIZE_INFO, index, sizeof(cp), &cp,
3972 adv_size_info_rsp, NULL, NULL)) {
3973 error("Unable to send advertising size info command");
3974 return noninteractive_quit(EXIT_FAILURE);
3978 static void add_adv_rsp(uint8_t status, uint16_t len, const void *param,
3981 const struct mgmt_rp_add_advertising *rp = param;
3984 error("Add Advertising failed with status 0x%02x (%s)",
3985 status, mgmt_errstr(status));
3986 return noninteractive_quit(EXIT_FAILURE);
3989 if (len != sizeof(*rp)) {
3990 error("Invalid Add Advertising response length (%u)", len);
3991 return noninteractive_quit(EXIT_FAILURE);
3994 print("Instance added: %u", rp->instance);
3996 return noninteractive_quit(EXIT_SUCCESS);
3999 static void add_adv_usage(void)
4001 print("Usage: add-adv [options] <instance_id>\nOptions:\n"
4002 "\t -u, --uuid <uuid> Service UUID\n"
4003 "\t -d, --adv-data <data> Advertising Data bytes\n"
4004 "\t -s, --scan-rsp <data> Scan Response Data bytes\n"
4005 "\t -t, --timeout <timeout> Timeout in seconds\n"
4006 "\t -D, --duration <duration> Duration in seconds\n"
4007 "\t -c, --connectable \"connectable\" flag\n"
4008 "\t -g, --general-discov \"general-discoverable\" flag\n"
4009 "\t -l, --limited-discov \"limited-discoverable\" flag\n"
4010 "\t -m, --managed-flags \"managed-flags\" flag\n"
4011 "\t -p, --tx-power \"tx-power\" flag\n"
4013 "\tadd-adv -u 180d -u 180f -d 080954657374204C45 1");
4016 static struct option add_adv_options[] = {
4017 { "help", 0, 0, 'h' },
4018 { "uuid", 1, 0, 'u' },
4019 { "adv-data", 1, 0, 'd' },
4020 { "scan-rsp", 1, 0, 's' },
4021 { "timeout", 1, 0, 't' },
4022 { "duration", 1, 0, 'D' },
4023 { "connectable", 0, 0, 'c' },
4024 { "general-discov", 0, 0, 'g' },
4025 { "limited-discov", 0, 0, 'l' },
4026 { "managed-flags", 0, 0, 'm' },
4027 { "tx-power", 0, 0, 'p' },
4031 static bool parse_bytes(char *optarg, uint8_t **bytes, size_t *len)
4040 *len = strlen(optarg);
4043 error("Malformed data");
4048 if (*len > UINT8_MAX) {
4049 error("Data too long");
4053 *bytes = malloc(*len);
4055 error("Failed to allocate memory");
4059 for (i = 0; i < *len; i++) {
4060 if (sscanf(optarg + (i * 2), "%2hhx", *bytes + i) != 1) {
4061 error("Invalid data");
4071 #define MAX_AD_UUID_BYTES 32
4073 static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
4074 int argc, char **argv)
4076 struct mgmt_cp_add_advertising *cp = NULL;
4078 uint8_t *adv_data = NULL, *scan_rsp = NULL;
4079 size_t adv_len = 0, scan_rsp_len = 0;
4081 uint8_t uuids[MAX_AD_UUID_BYTES];
4082 size_t uuid_bytes = 0;
4083 uint8_t uuid_type = 0;
4084 uint16_t timeout = 0, duration = 0;
4087 bool success = false;
4091 while ((opt = getopt_long(argc, argv, "+u:d:s:t:D:cglmph",
4092 add_adv_options, NULL)) != -1) {
4095 if (bt_string2uuid(&uuid, optarg) < 0) {
4096 print("Invalid UUID: %s", optarg);
4100 if (uuid_type && uuid_type != uuid.type) {
4101 print("UUID types must be consistent");
4105 if (uuid.type == SDP_UUID16) {
4106 if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) {
4107 print("Too many UUIDs");
4111 put_le16(uuid.value.uuid16, uuids + uuid_bytes);
4113 } else if (uuid.type == SDP_UUID128) {
4114 if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) {
4115 print("Too many UUIDs");
4119 bswap_128(uuid.value.uuid128.data,
4120 uuids + uuid_bytes);
4123 printf("Unsupported UUID type");
4128 uuid_type = uuid.type;
4133 print("Only one adv-data option allowed");
4137 if (!parse_bytes(optarg, &adv_data, &adv_len))
4142 print("Only one scan-rsp option allowed");
4146 if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len))
4150 timeout = strtol(optarg, NULL, 0);
4153 duration = strtol(optarg, NULL, 0);
4156 flags |= MGMT_ADV_FLAG_CONNECTABLE;
4159 flags |= MGMT_ADV_FLAG_DISCOV;
4162 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
4165 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
4168 flags |= MGMT_ADV_FLAG_TX_POWER;
4190 instance = strtol(argv[0], NULL, 0);
4192 if (index == MGMT_INDEX_NONE)
4195 cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len;
4196 cp = malloc0(cp_len);
4200 cp->instance = instance;
4201 put_le32(flags, &cp->flags);
4202 put_le16(timeout, &cp->timeout);
4203 put_le16(duration, &cp->duration);
4204 cp->adv_data_len = adv_len + uuid_bytes;
4205 cp->scan_rsp_len = scan_rsp_len;
4208 cp->data[0] = uuid_bytes - 1;
4209 cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07;
4210 memcpy(cp->data + 2, uuids, uuid_bytes - 2);
4213 memcpy(cp->data + uuid_bytes, adv_data, adv_len);
4214 memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len);
4216 if (!mgmt_send(mgmt, MGMT_OP_ADD_ADVERTISING, index, cp_len, cp,
4217 add_adv_rsp, NULL, NULL)) {
4218 error("Unable to send \"Add Advertising\" command");
4230 noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE);
4233 static void rm_adv_rsp(uint8_t status, uint16_t len, const void *param,
4236 const struct mgmt_rp_remove_advertising *rp = param;
4239 error("Remove Advertising failed with status 0x%02x (%s)",
4240 status, mgmt_errstr(status));
4241 return noninteractive_quit(EXIT_FAILURE);
4244 if (len != sizeof(*rp)) {
4245 error("Invalid Remove Advertising response length (%u)", len);
4246 return noninteractive_quit(EXIT_FAILURE);
4249 print("Instance removed: %u", rp->instance);
4251 return noninteractive_quit(EXIT_SUCCESS);
4254 static void rm_adv_usage(void)
4256 print("Usage: rm-adv <instance_id>");
4259 static void cmd_rm_adv(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
4261 struct mgmt_cp_remove_advertising cp;
4266 return noninteractive_quit(EXIT_FAILURE);
4269 instance = strtol(argv[1], NULL, 0);
4271 if (index == MGMT_INDEX_NONE)
4274 memset(&cp, 0, sizeof(cp));
4276 cp.instance = instance;
4278 if (!mgmt_send(mgmt, MGMT_OP_REMOVE_ADVERTISING, index, sizeof(cp), &cp,
4279 rm_adv_rsp, NULL, NULL)) {
4280 error("Unable to send \"Remove Advertising\" command");
4281 return noninteractive_quit(EXIT_FAILURE);
4285 static void cmd_clr_adv(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
4287 char *all_instances = "0";
4288 char *rm_argv[] = { "rm-adv", all_instances, NULL };
4290 cmd_rm_adv(mgmt, index, 2, rm_argv);
4295 void (*func)(struct mgmt *mgmt, uint16_t index, int argc, char **argv);
4297 char * (*gen) (const char *text, int state);
4298 void (*disp) (char **matches, int num_matches, int max_length);
4301 static struct cmd_info all_cmd[] = {
4302 { "version", cmd_version, "Get the MGMT Version" },
4303 { "commands", cmd_commands, "List supported commands" },
4304 { "config", cmd_config, "Show configuration info" },
4305 { "info", cmd_info, "Show controller info" },
4306 { "extinfo", cmd_extinfo, "Show extended controller info" },
4307 { "auto-power", cmd_auto_power, "Power all available features" },
4308 { "power", cmd_power, "Toggle powered state" },
4309 { "discov", cmd_discov, "Toggle discoverable state" },
4310 { "connectable",cmd_connectable,"Toggle connectable state" },
4311 { "fast-conn", cmd_fast_conn, "Toggle fast connectable state" },
4312 { "bondable", cmd_bondable, "Toggle bondable state" },
4313 { "pairable", cmd_bondable, "Toggle bondable state" },
4314 { "linksec", cmd_linksec, "Toggle link level security" },
4315 { "ssp", cmd_ssp, "Toggle SSP mode" },
4316 { "sc", cmd_sc, "Toogle SC support" },
4317 { "hs", cmd_hs, "Toggle HS support" },
4318 { "le", cmd_le, "Toggle LE support" },
4319 { "advertising",cmd_advertising,"Toggle LE advertising", },
4320 { "bredr", cmd_bredr, "Toggle BR/EDR support", },
4321 { "privacy", cmd_privacy, "Toggle privacy support" },
4322 { "class", cmd_class, "Set device major/minor class" },
4323 { "disconnect", cmd_disconnect, "Disconnect device" },
4324 { "con", cmd_con, "List connections" },
4325 { "find", cmd_find, "Discover nearby devices" },
4326 { "find-service", cmd_find_service, "Discover nearby service" },
4327 { "stop-find", cmd_stop_find, "Stop discovery" },
4328 { "name", cmd_name, "Set local name" },
4329 { "pair", cmd_pair, "Pair with a remote device" },
4330 { "cancelpair", cmd_cancel_pair,"Cancel pairing" },
4331 { "unpair", cmd_unpair, "Unpair device" },
4332 { "keys", cmd_keys, "Load Link Keys" },
4333 { "ltks", cmd_ltks, "Load Long Term Keys" },
4334 { "irks", cmd_irks, "Load Identity Resolving Keys" },
4335 { "block", cmd_block, "Block Device" },
4336 { "unblock", cmd_unblock, "Unblock Device" },
4337 { "add-uuid", cmd_add_uuid, "Add UUID" },
4338 { "rm-uuid", cmd_remove_uuid,"Remove UUID" },
4339 { "clr-uuids", cmd_clr_uuids, "Clear UUIDs" },
4340 { "local-oob", cmd_local_oob, "Local OOB data" },
4341 { "remote-oob", cmd_remote_oob, "Remote OOB data" },
4342 { "did", cmd_did, "Set Device ID" },
4343 { "static-addr",cmd_static_addr,"Set static address" },
4344 { "public-addr",cmd_public_addr,"Set public address" },
4345 { "ext-config", cmd_ext_config, "External configuration" },
4346 { "debug-keys", cmd_debug_keys, "Toogle debug keys" },
4347 { "conn-info", cmd_conn_info, "Get connection information" },
4348 { "io-cap", cmd_io_cap, "Set IO Capability" },
4349 { "scan-params",cmd_scan_params,"Set Scan Parameters" },
4350 { "get-clock", cmd_clock_info, "Get Clock Information" },
4351 { "add-device", cmd_add_device, "Add Device" },
4352 { "del-device", cmd_del_device, "Remove Device" },
4353 { "clr-devices",cmd_clr_devices,"Clear Devices" },
4354 { "bredr-oob", cmd_bredr_oob, "Local OOB data (BR/EDR)" },
4355 { "le-oob", cmd_le_oob, "Local OOB data (LE)" },
4356 { "advinfo", cmd_advinfo, "Show advertising features" },
4357 { "advsize", cmd_advsize, "Show advertising size info" },
4358 { "add-adv", cmd_add_adv, "Add advertising instance" },
4359 { "rm-adv", cmd_rm_adv, "Remove advertising instance" },
4360 { "clr-adv", cmd_clr_adv, "Clear advertising instances" },
4363 static void cmd_quit(struct mgmt *mgmt, uint16_t index,
4364 int argc, char **argv)
4366 mainloop_exit_success();
4369 static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index)
4371 mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error,
4373 mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added,
4375 mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed,
4377 mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings,
4379 mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering,
4381 mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key,
4383 mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected,
4385 mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected,
4387 mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed,
4389 mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed,
4391 mgmt_register(mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED, index,
4392 class_of_dev_changed, NULL, NULL);
4393 mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index,
4394 local_name_changed, NULL, NULL);
4395 mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found,
4397 mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin,
4399 mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm,
4401 mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index,
4402 request_passkey, mgmt, NULL);
4403 mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index,
4404 passkey_notify, mgmt, NULL);
4405 mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index,
4406 unconf_index_added, NULL, NULL);
4407 mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index,
4408 unconf_index_removed, NULL, NULL);
4409 mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index,
4410 new_config_options, NULL, NULL);
4411 mgmt_register(mgmt, MGMT_EV_EXT_INDEX_ADDED, index,
4412 ext_index_added, NULL, NULL);
4413 mgmt_register(mgmt, MGMT_EV_EXT_INDEX_REMOVED, index,
4414 ext_index_removed, NULL, NULL);
4415 mgmt_register(mgmt, MGMT_EV_LOCAL_OOB_DATA_UPDATED, index,
4416 local_oob_data_updated, NULL, NULL);
4417 mgmt_register(mgmt, MGMT_EV_ADVERTISING_ADDED, index,
4418 advertising_added, NULL, NULL);
4419 mgmt_register(mgmt, MGMT_EV_ADVERTISING_REMOVED, index,
4420 advertising_removed, NULL, NULL);
4423 static void cmd_select(struct mgmt *mgmt, uint16_t index,
4424 int argc, char **argv)
4427 error("Usage: select <index>");
4431 mgmt_cancel_all(mgmt);
4432 mgmt_unregister_all(mgmt);
4434 if (!strcmp(argv[1], "none") || !strcmp(argv[1], "any") ||
4435 !strcmp(argv[1], "all"))
4436 mgmt_index = MGMT_INDEX_NONE;
4437 else if (!strncmp(argv[1], "hci", 3))
4438 mgmt_index = atoi(&argv[1][3]);
4440 mgmt_index = atoi(argv[1]);
4442 register_mgmt_callbacks(mgmt, mgmt_index);
4444 print("Selected index %u", mgmt_index);
4446 update_prompt(mgmt_index);
4449 static struct cmd_info interactive_cmd[] = {
4450 { "select", cmd_select, "Select a different index" },
4451 { "quit", cmd_quit, "Exit program" },
4452 { "exit", cmd_quit, "Exit program" },
4453 { "help", NULL, "List supported commands" },
4456 static char *cmd_generator(const char *text, int state)
4458 static size_t i, j, len;
4467 while (i < NELEM(all_cmd)) {
4468 cmd = all_cmd[i++].cmd;
4470 if (!strncmp(cmd, text, len))
4474 while (j < NELEM(interactive_cmd)) {
4475 cmd = interactive_cmd[j++].cmd;
4477 if (!strncmp(cmd, text, len))
4484 static char **cmd_completion(const char *text, int start, int end)
4486 char **matches = NULL;
4491 for (i = 0; i < NELEM(all_cmd); i++) {
4492 struct cmd_info *c = &all_cmd[i];
4494 if (strncmp(c->cmd, rl_line_buffer, start - 1))
4500 rl_completion_display_matches_hook = c->disp;
4501 matches = rl_completion_matches(text, c->gen);
4505 rl_completion_display_matches_hook = NULL;
4506 matches = rl_completion_matches(text, cmd_generator);
4510 rl_attempted_completion_over = 1;
4515 static struct cmd_info *find_cmd(const char *cmd, struct cmd_info table[],
4520 for (i = 0; i < cmd_count; i++) {
4521 if (!strcmp(table[i].cmd, cmd))
4528 static void rl_handler(char *input)
4536 rl_insert_text("quit");
4546 if (prompt_input(input))
4551 if (wordexp(input, &w, WRDE_NOCMD))
4554 if (w.we_wordc == 0)
4557 cmd = w.we_wordv[0];
4561 c = find_cmd(cmd, all_cmd, NELEM(all_cmd));
4562 if (!c && interactive)
4563 c = find_cmd(cmd, interactive_cmd, NELEM(interactive_cmd));
4566 c->func(mgmt, mgmt_index, argc, argv);
4570 if (strcmp(cmd, "help")) {
4571 print("Invalid command");
4575 print("Available commands:");
4577 for (i = 0; i < NELEM(all_cmd); i++) {
4580 print(" %s %-*s %s", c->cmd,
4581 (int)(25 - strlen(c->cmd)), "", c->doc ? : "");
4587 for (i = 0; i < NELEM(interactive_cmd); i++) {
4588 c = &interactive_cmd[i];
4590 print(" %s %-*s %s", c->cmd,
4591 (int)(25 - strlen(c->cmd)), "", c->doc ? : "");
4600 static void usage(void)
4604 printf("btmgmt ver %s\n", VERSION);
4606 "\tbtmgmt [options] <command> [command parameters]\n");
4609 "\t--index <id>\tSpecify adapter index\n"
4610 "\t--verbose\tEnable extra logging\n"
4611 "\t--help\tDisplay help\n");
4613 printf("Commands:\n");
4614 for (i = 0; i < NELEM(all_cmd); i++)
4615 printf("\t%-15s\t%s\n", all_cmd[i].cmd, all_cmd[i].doc);
4618 "For more information on the usage of each command use:\n"
4619 "\tbtmgmt <command> --help\n" );
4622 static struct option main_options[] = {
4623 { "index", 1, 0, 'i' },
4624 { "verbose", 0, 0, 'v' },
4625 { "help", 0, 0, 'h' },
4629 static bool prompt_read(struct io *io, void *user_data)
4631 rl_callback_read_char();
4635 static struct io *setup_stdin(void)
4639 io = io_new(STDIN_FILENO);
4643 io_set_read_handler(io, prompt_read, NULL, NULL);
4648 static void mgmt_debug(const char *str, void *user_data)
4650 const char *prefix = user_data;
4652 print("%s%s", prefix, str);
4655 int main(int argc, char *argv[])
4658 uint16_t index = MGMT_INDEX_NONE;
4661 while ((opt = getopt_long(argc, argv, "+hi:",
4662 main_options, NULL)) != -1) {
4665 if (strlen(optarg) > 3 &&
4666 strncasecmp(optarg, "hci", 3) == 0)
4667 index = atoi(optarg + 3);
4669 index = atoi(optarg);
4684 mgmt = mgmt_new_default();
4686 fprintf(stderr, "Unable to open mgmt_socket\n");
4687 return EXIT_FAILURE;
4690 if (getenv("MGMT_DEBUG"))
4691 mgmt_set_debug(mgmt, mgmt_debug, "mgmt: ", NULL);
4696 c = find_cmd(argv[0], all_cmd, NELEM(all_cmd));
4698 fprintf(stderr, "Unknown command: %s\n", argv[0]);
4700 return EXIT_FAILURE;
4703 c->func(mgmt, index, argc, argv);
4706 register_mgmt_callbacks(mgmt, index);
4708 /* Interactive mode */
4710 input = setup_stdin();
4717 rl_attempted_completion_function = cmd_completion;
4719 rl_erase_empty_line = 1;
4720 rl_callback_handler_install(NULL, rl_handler);
4722 update_prompt(index);
4728 status = mainloop_run();
4734 rl_callback_handler_remove();
4737 mgmt_cancel_all(mgmt);
4738 mgmt_unregister_all(mgmt);