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(const char *path, struct mgmt_irk_info *irk)
233 fp = fopen(path, "r");
235 error("Failed to open identity file: %s", strerror(errno));
239 n = fscanf(fp, "%m[0-9a-f:] (type %u) %m[0-9a-f]", &addr, &type, &key);
246 str2ba(addr, &irk->addr.bdaddr);
247 hex2bin(key, irk->val, sizeof(irk->val));
254 irk->addr.type = BDADDR_LE_PUBLIC;
257 irk->addr.type = BDADDR_LE_RANDOM;
260 error("Invalid address type %u", type);
267 static void controller_error(uint16_t index, uint16_t len,
268 const void *param, void *user_data)
270 const struct mgmt_ev_controller_error *ev = param;
272 if (len < sizeof(*ev)) {
273 error("Too short (%u bytes) controller error event", len);
277 print("hci%u error 0x%02x", index, ev->error_code);
280 static void index_added(uint16_t index, uint16_t len,
281 const void *param, void *user_data)
283 print("hci%u added", index);
286 static void index_removed(uint16_t index, uint16_t len,
287 const void *param, void *user_data)
289 print("hci%u removed", index);
292 static void unconf_index_added(uint16_t index, uint16_t len,
293 const void *param, void *user_data)
295 print("hci%u added (unconfigured)", index);
298 static void unconf_index_removed(uint16_t index, uint16_t len,
299 const void *param, void *user_data)
301 print("hci%u removed (unconfigured)", index);
304 static void ext_index_added(uint16_t index, uint16_t len,
305 const void *param, void *user_data)
307 const struct mgmt_ev_ext_index_added *ev = param;
309 print("hci%u added (type %u bus %u)", index, ev->type, ev->bus);
312 static void ext_index_removed(uint16_t index, uint16_t len,
313 const void *param, void *user_data)
315 const struct mgmt_ev_ext_index_removed *ev = param;
317 print("hci%u removed (type %u bus %u)", index, ev->type, ev->bus);
320 static const char *options_str[] = {
325 static const char *options2str(uint32_t options)
327 static char str[256];
334 for (i = 0; i < NELEM(options_str); i++) {
335 if ((options & (1 << i)) != 0)
336 off += snprintf(str + off, sizeof(str) - off, "%s ",
343 static void new_config_options(uint16_t index, uint16_t len,
344 const void *param, void *user_data)
346 const uint32_t *ev = param;
348 if (len < sizeof(*ev)) {
349 error("Too short new_config_options event (%u)", len);
353 print("hci%u new_config_options: %s", index, options2str(get_le32(ev)));
356 static const char *settings_str[] = {
375 static const char *settings2str(uint32_t settings)
377 static char str[256];
384 for (i = 0; i < NELEM(settings_str); i++) {
385 if ((settings & (1 << i)) != 0)
386 off += snprintf(str + off, sizeof(str) - off, "%s ",
393 static void new_settings(uint16_t index, uint16_t len,
394 const void *param, void *user_data)
396 const uint32_t *ev = param;
398 if (len < sizeof(*ev)) {
399 error("Too short new_settings event (%u)", len);
403 print("hci%u new_settings: %s", index, settings2str(get_le32(ev)));
406 static void discovering(uint16_t index, uint16_t len, const void *param,
409 const struct mgmt_ev_discovering *ev = param;
411 if (len < sizeof(*ev)) {
412 error("Too short (%u bytes) discovering event", len);
416 print("hci%u type %u discovering %s", index, ev->type,
417 ev->discovering ? "on" : "off");
419 if (ev->discovering == 0 && discovery)
420 return noninteractive_quit(EXIT_SUCCESS);
423 static void new_link_key(uint16_t index, uint16_t len, const void *param,
426 const struct mgmt_ev_new_link_key *ev = param;
429 if (len != sizeof(*ev)) {
430 error("Invalid new_link_key length (%u bytes)", len);
434 ba2str(&ev->key.addr.bdaddr, addr);
435 print("hci%u new_link_key %s type 0x%02x pin_len %d store_hint %u",
436 index, addr, ev->key.type, ev->key.pin_len, ev->store_hint);
439 static const char *typestr(uint8_t type)
441 static const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
443 if (type <= BDADDR_LE_RANDOM)
449 static void connected(uint16_t index, uint16_t len, const void *param,
452 const struct mgmt_ev_device_connected *ev = param;
456 if (len < sizeof(*ev)) {
457 error("Invalid connected event length (%u bytes)", len);
461 eir_len = get_le16(&ev->eir_len);
462 if (len != sizeof(*ev) + eir_len) {
463 error("Invalid connected event length (%u != eir_len %u)",
468 ba2str(&ev->addr.bdaddr, addr);
469 print("hci%u %s type %s connected eir_len %u", index, addr,
470 typestr(ev->addr.type), eir_len);
473 static void release_prompt(void)
478 memset(&prompt, 0, sizeof(prompt));
479 prompt.index = MGMT_INDEX_NONE;
484 /* This will cause rl_expand_prompt to re-run over the last prompt,
485 * but our prompt doesn't expand anyway.
487 rl_set_prompt(saved_prompt);
488 rl_replace_line("", 0);
489 rl_point = saved_point;
496 static void disconnected(uint16_t index, uint16_t len, const void *param,
499 const struct mgmt_ev_device_disconnected *ev = param;
503 if (len < sizeof(struct mgmt_addr_info)) {
504 error("Invalid disconnected event length (%u bytes)", len);
508 if (!memcmp(&ev->addr, &prompt.addr, sizeof(ev->addr)))
511 if (len < sizeof(*ev))
512 reason = MGMT_DEV_DISCONN_UNKNOWN;
516 ba2str(&ev->addr.bdaddr, addr);
517 print("hci%u %s type %s disconnected with reason %u",
518 index, addr, typestr(ev->addr.type), reason);
521 static void conn_failed(uint16_t index, uint16_t len, const void *param,
524 const struct mgmt_ev_connect_failed *ev = param;
527 if (len != sizeof(*ev)) {
528 error("Invalid connect_failed event length (%u bytes)", len);
532 ba2str(&ev->addr.bdaddr, addr);
533 print("hci%u %s type %s connect failed (status 0x%02x, %s)",
534 index, addr, typestr(ev->addr.type), ev->status,
535 mgmt_errstr(ev->status));
538 static void auth_failed(uint16_t index, uint16_t len, const void *param,
541 const struct mgmt_ev_auth_failed *ev = param;
544 if (len != sizeof(*ev)) {
545 error("Invalid auth_failed event length (%u bytes)", len);
549 if (!memcmp(&ev->addr, &prompt.addr, sizeof(ev->addr)))
552 ba2str(&ev->addr.bdaddr, addr);
553 print("hci%u %s auth failed with status 0x%02x (%s)",
554 index, addr, ev->status, mgmt_errstr(ev->status));
557 static void class_of_dev_changed(uint16_t index, uint16_t len,
558 const void *param, void *user_data)
560 const struct mgmt_ev_class_of_dev_changed *ev = param;
562 if (len != sizeof(*ev)) {
563 error("Invalid class_of_dev_changed length (%u bytes)", len);
567 print("hci%u class of device changed: 0x%02x%02x%02x", index,
568 ev->dev_class[2], ev->dev_class[1], ev->dev_class[0]);
571 static void local_name_changed(uint16_t index, uint16_t len, const void *param,
574 const struct mgmt_ev_local_name_changed *ev = param;
576 if (len != sizeof(*ev)) {
577 error("Invalid local_name_changed length (%u bytes)", len);
581 print("hci%u name changed: %s", index, ev->name);
584 static void confirm_name_rsp(uint8_t status, uint16_t len,
585 const void *param, void *user_data)
587 const struct mgmt_rp_confirm_name *rp = param;
590 if (len == 0 && status != 0) {
591 error("confirm_name failed with status 0x%02x (%s)", status,
592 mgmt_errstr(status));
596 if (len != sizeof(*rp)) {
597 error("confirm_name rsp length %u instead of %zu",
602 ba2str(&rp->addr.bdaddr, addr);
605 error("confirm_name for %s failed: 0x%02x (%s)",
606 addr, status, mgmt_errstr(status));
608 print("confirm_name succeeded for %s", addr);
611 static char *eir_get_name(const uint8_t *eir, uint16_t eir_len)
618 while (parsed < eir_len - 1) {
619 uint8_t field_len = eir[0];
624 parsed += field_len + 1;
626 if (parsed > eir_len)
629 /* Check for short of complete name */
630 if (eir[1] == 0x09 || eir[1] == 0x08)
631 return strndup((char *) &eir[2], field_len - 1);
633 eir += field_len + 1;
639 static unsigned int eir_get_flags(const uint8_t *eir, uint16_t eir_len)
646 while (parsed < eir_len - 1) {
647 uint8_t field_len = eir[0];
652 parsed += field_len + 1;
654 if (parsed > eir_len)
657 /* Check for flags */
661 eir += field_len + 1;
667 static void device_found(uint16_t index, uint16_t len, const void *param,
670 const struct mgmt_ev_device_found *ev = param;
671 struct mgmt *mgmt = user_data;
675 if (len < sizeof(*ev)) {
676 error("Too short device_found length (%u bytes)", len);
680 flags = btohl(ev->flags);
682 eir_len = get_le16(&ev->eir_len);
683 if (len != sizeof(*ev) + eir_len) {
684 error("dev_found: expected %zu bytes, got %u bytes",
685 sizeof(*ev) + eir_len, len);
690 char addr[18], *name;
692 ba2str(&ev->addr.bdaddr, addr);
693 print("hci%u dev_found: %s type %s rssi %d "
694 "flags 0x%04x ", index, addr,
695 typestr(ev->addr.type), ev->rssi, flags);
697 if (ev->addr.type != BDADDR_BREDR)
698 print("AD flags 0x%02x ",
699 eir_get_flags(ev->eir, eir_len));
701 name = eir_get_name(ev->eir, eir_len);
703 print("name %s", name);
705 print("eir_len %u", eir_len);
710 if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) {
711 struct mgmt_cp_confirm_name cp;
713 memset(&cp, 0, sizeof(cp));
714 memcpy(&cp.addr, &ev->addr, sizeof(cp.addr));
720 mgmt_reply(mgmt, MGMT_OP_CONFIRM_NAME, index, sizeof(cp), &cp,
721 confirm_name_rsp, NULL, NULL);
725 static void pin_rsp(uint8_t status, uint16_t len, const void *param,
729 error("PIN Code reply failed with status 0x%02x (%s)",
730 status, mgmt_errstr(status));
731 return noninteractive_quit(EXIT_FAILURE);
734 print("PIN Reply successful");
737 static int mgmt_pin_reply(struct mgmt *mgmt, uint16_t index,
738 const struct mgmt_addr_info *addr,
739 const char *pin, size_t len)
741 struct mgmt_cp_pin_code_reply cp;
743 memset(&cp, 0, sizeof(cp));
744 memcpy(&cp.addr, addr, sizeof(cp.addr));
746 memcpy(cp.pin_code, pin, len);
748 return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_REPLY, index, sizeof(cp), &cp,
749 pin_rsp, NULL, NULL);
752 static void pin_neg_rsp(uint8_t status, uint16_t len, const void *param,
756 error("PIN Neg reply failed with status 0x%02x (%s)",
757 status, mgmt_errstr(status));
758 return noninteractive_quit(EXIT_FAILURE);
761 print("PIN Negative Reply successful");
764 static int mgmt_pin_neg_reply(struct mgmt *mgmt, uint16_t index,
765 const struct mgmt_addr_info *addr)
767 struct mgmt_cp_pin_code_neg_reply cp;
769 memset(&cp, 0, sizeof(cp));
770 memcpy(&cp.addr, addr, sizeof(cp.addr));
772 return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_NEG_REPLY, index,
773 sizeof(cp), &cp, pin_neg_rsp, NULL, NULL);
776 static void confirm_rsp(uint8_t status, uint16_t len, const void *param,
780 error("User Confirm reply failed. status 0x%02x (%s)",
781 status, mgmt_errstr(status));
782 return noninteractive_quit(EXIT_FAILURE);
785 print("User Confirm Reply successful");
788 static int mgmt_confirm_reply(struct mgmt *mgmt, uint16_t index,
789 const struct mgmt_addr_info *addr)
791 struct mgmt_cp_user_confirm_reply cp;
793 memset(&cp, 0, sizeof(cp));
794 memcpy(&cp.addr, addr, sizeof(*addr));
796 return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_REPLY, index,
797 sizeof(cp), &cp, confirm_rsp, NULL, NULL);
800 static void confirm_neg_rsp(uint8_t status, uint16_t len, const void *param,
804 error("Confirm Neg reply failed. status 0x%02x (%s)",
805 status, mgmt_errstr(status));
806 return noninteractive_quit(EXIT_FAILURE);
809 print("User Confirm Negative Reply successful");
812 static int mgmt_confirm_neg_reply(struct mgmt *mgmt, uint16_t index,
813 const struct mgmt_addr_info *addr)
815 struct mgmt_cp_user_confirm_reply cp;
817 memset(&cp, 0, sizeof(cp));
818 memcpy(&cp.addr, addr, sizeof(*addr));
820 return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_NEG_REPLY, index,
821 sizeof(cp), &cp, confirm_neg_rsp, NULL, NULL);
824 static void passkey_rsp(uint8_t status, uint16_t len, const void *param,
828 error("User Passkey reply failed. status 0x%02x (%s)",
829 status, mgmt_errstr(status));
830 return noninteractive_quit(EXIT_FAILURE);
833 print("User Passkey Reply successful");
836 static int mgmt_passkey_reply(struct mgmt *mgmt, uint16_t index,
837 const struct mgmt_addr_info *addr,
840 struct mgmt_cp_user_passkey_reply cp;
842 memset(&cp, 0, sizeof(cp));
843 memcpy(&cp.addr, addr, sizeof(*addr));
844 put_le32(passkey, &cp.passkey);
846 return mgmt_reply(mgmt, MGMT_OP_USER_PASSKEY_REPLY, index,
847 sizeof(cp), &cp, passkey_rsp, NULL, NULL);
850 static void passkey_neg_rsp(uint8_t status, uint16_t len, const void *param,
854 error("Passkey Neg reply failed. status 0x%02x (%s)",
855 status, mgmt_errstr(status));
856 return noninteractive_quit(EXIT_FAILURE);
859 print("User Passkey Negative Reply successful");
862 static int mgmt_passkey_neg_reply(struct mgmt *mgmt, uint16_t index,
863 const struct mgmt_addr_info *addr)
865 struct mgmt_cp_user_passkey_reply cp;
867 memset(&cp, 0, sizeof(cp));
868 memcpy(&cp.addr, addr, sizeof(*addr));
870 return mgmt_reply(mgmt, MGMT_OP_USER_PASSKEY_NEG_REPLY, index,
871 sizeof(cp), &cp, passkey_neg_rsp, NULL, NULL);
874 static bool prompt_input(const char *input)
883 switch (prompt.req) {
884 case MGMT_EV_PIN_CODE_REQUEST:
886 mgmt_pin_reply(mgmt, prompt.index, &prompt.addr,
889 mgmt_pin_neg_reply(mgmt, prompt.index, &prompt.addr);
891 case MGMT_EV_USER_PASSKEY_REQUEST:
892 if (strlen(input) > 0)
893 mgmt_passkey_reply(mgmt, prompt.index, &prompt.addr,
896 mgmt_passkey_neg_reply(mgmt, prompt.index,
899 case MGMT_EV_USER_CONFIRM_REQUEST:
900 if (input[0] == 'y' || input[0] == 'Y')
901 mgmt_confirm_reply(mgmt, prompt.index, &prompt.addr);
903 mgmt_confirm_neg_reply(mgmt, prompt.index,
913 static void interactive_prompt(const char *msg)
918 saved_prompt = strdup(rl_prompt);
922 saved_point = rl_point;
929 rl_replace_line("", 0);
933 static size_t get_input(char *buf, size_t buf_len)
937 if (!fgets(buf, buf_len, stdin))
942 /* Remove trailing white-space */
943 while (len && isspace(buf[len - 1]))
949 static void ask(uint16_t index, uint16_t req, const struct mgmt_addr_info *addr,
950 const char *fmt, ...)
952 char msg[256], buf[18];
956 prompt.index = index;
958 memcpy(&prompt.addr, addr, sizeof(*addr));
961 off = vsnprintf(msg, sizeof(msg), fmt, ap);
964 snprintf(msg + off, sizeof(msg) - off, " %s ",
965 COLOR_BOLDGRAY ">>" COLOR_OFF);
968 interactive_prompt(msg);
976 memset(buf, 0, sizeof(buf));
977 get_input(buf, sizeof(buf));
981 static void request_pin(uint16_t index, uint16_t len, const void *param,
984 const struct mgmt_ev_pin_code_request *ev = param;
987 if (len != sizeof(*ev)) {
988 error("Invalid pin_code request length (%u bytes)", len);
992 ba2str(&ev->addr.bdaddr, addr);
993 print("hci%u %s request PIN", index, addr);
995 ask(index, MGMT_EV_PIN_CODE_REQUEST, &ev->addr,
996 "PIN Request (press enter to reject)");
999 static void user_confirm(uint16_t index, uint16_t len, const void *param,
1002 const struct mgmt_ev_user_confirm_request *ev = param;
1006 if (len != sizeof(*ev)) {
1007 error("Invalid user_confirm request length (%u)", len);
1011 ba2str(&ev->addr.bdaddr, addr);
1012 val = get_le32(&ev->value);
1014 print("hci%u %s User Confirm %06u hint %u", index, addr,
1015 val, ev->confirm_hint);
1017 if (ev->confirm_hint)
1018 ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr,
1019 "Accept pairing with %s (yes/no)", addr);
1021 ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr,
1022 "Confirm value %06u for %s (yes/no)", val, addr);
1025 static void request_passkey(uint16_t index, uint16_t len, const void *param,
1028 const struct mgmt_ev_user_passkey_request *ev = param;
1031 if (len != sizeof(*ev)) {
1032 error("Invalid passkey request length (%u bytes)", len);
1036 ba2str(&ev->addr.bdaddr, addr);
1037 print("hci%u %s request passkey", index, addr);
1039 ask(index, MGMT_EV_USER_PASSKEY_REQUEST, &ev->addr,
1040 "Passkey Request (press enter to reject)");
1043 static void passkey_notify(uint16_t index, uint16_t len, const void *param,
1046 const struct mgmt_ev_passkey_notify *ev = param;
1049 if (len != sizeof(*ev)) {
1050 error("Invalid passkey request length (%u bytes)", len);
1054 ba2str(&ev->addr.bdaddr, addr);
1055 print("hci%u %s request passkey", index, addr);
1057 print("Passkey Notify: %06u (entered %u)", get_le32(&ev->passkey),
1061 static void local_oob_data_updated(uint16_t index, uint16_t len,
1062 const void *param, void *user_data)
1064 const struct mgmt_ev_local_oob_data_updated *ev = param;
1067 if (len < sizeof(*ev)) {
1068 error("Too small (%u bytes) local_oob_updated event", len);
1072 eir_len = le16_to_cpu(ev->eir_len);
1073 if (len != sizeof(*ev) + eir_len) {
1074 error("local_oob_updated: expected %zu bytes, got %u bytes",
1075 sizeof(*ev) + eir_len, len);
1079 print("hci%u oob data updated: type %u len %u", index,
1083 static void advertising_added(uint16_t index, uint16_t len,
1084 const void *param, void *user_data)
1086 const struct mgmt_ev_advertising_added *ev = param;
1088 if (len < sizeof(*ev)) {
1089 error("Too small (%u bytes) advertising_added event", len);
1093 print("hci%u advertising_added: instance %u", index, ev->instance);
1096 static void advertising_removed(uint16_t index, uint16_t len,
1097 const void *param, void *user_data)
1099 const struct mgmt_ev_advertising_removed *ev = param;
1101 if (len < sizeof(*ev)) {
1102 error("Too small (%u bytes) advertising_removed event", len);
1106 print("hci%u advertising_removed: instance %u", index, ev->instance);
1109 static void version_rsp(uint8_t status, uint16_t len, const void *param,
1112 const struct mgmt_rp_read_version *rp = param;
1115 error("Reading mgmt version failed with status 0x%02x (%s)",
1116 status, mgmt_errstr(status));
1120 if (len < sizeof(*rp)) {
1121 error("Too small version reply (%u bytes)", len);
1125 print("MGMT Version %u, revision %u", rp->version,
1126 get_le16(&rp->revision));
1129 noninteractive_quit(EXIT_SUCCESS);
1132 static void cmd_version(struct mgmt *mgmt, uint16_t index, int argc,
1135 if (mgmt_send(mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE,
1136 0, NULL, version_rsp, NULL, NULL) == 0) {
1137 error("Unable to send read_version cmd");
1138 return noninteractive_quit(EXIT_FAILURE);
1142 static void commands_rsp(uint8_t status, uint16_t len, const void *param,
1145 const struct mgmt_rp_read_commands *rp = param;
1146 uint16_t num_commands, num_events;
1147 const uint16_t *opcode;
1148 size_t expected_len;
1152 error("Read Supported Commands failed: status 0x%02x (%s)",
1153 status, mgmt_errstr(status));
1157 if (len < sizeof(*rp)) {
1158 error("Too small commands reply (%u bytes)", len);
1162 num_commands = get_le16(&rp->num_commands);
1163 num_events = get_le16(&rp->num_events);
1165 expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
1166 num_events * sizeof(uint16_t);
1168 if (len < expected_len) {
1169 error("Too small commands reply (%u != %zu)",
1174 opcode = rp->opcodes;
1176 print("%u commands:", num_commands);
1177 for (i = 0; i < num_commands; i++) {
1178 uint16_t op = get_le16(opcode++);
1179 print("\t%s (0x%04x)", mgmt_opstr(op), op);
1182 print("%u events:", num_events);
1183 for (i = 0; i < num_events; i++) {
1184 uint16_t ev = get_le16(opcode++);
1185 print("\t%s (0x%04x)", mgmt_evstr(ev), ev);
1189 noninteractive_quit(EXIT_SUCCESS);
1192 static void cmd_commands(struct mgmt *mgmt, uint16_t index, int argc,
1195 if (mgmt_send(mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE,
1196 0, NULL, commands_rsp, NULL, NULL) == 0) {
1197 error("Unable to send read_commands cmd");
1198 return noninteractive_quit(EXIT_FAILURE);
1202 static void config_info_rsp(uint8_t status, uint16_t len, const void *param,
1205 const struct mgmt_rp_read_config_info *rp = param;
1206 uint16_t index = PTR_TO_UINT(user_data);
1207 uint32_t supported_options, missing_options;
1210 error("Reading hci%u config failed with status 0x%02x (%s)",
1211 index, status, mgmt_errstr(status));
1215 if (len < sizeof(*rp)) {
1216 error("Too small info reply (%u bytes)", len);
1220 print("hci%u:\tUnconfigured controller", index);
1222 print("\tmanufacturer %u", le16_to_cpu(rp->manufacturer));
1224 supported_options = le32_to_cpu(rp->supported_options);
1225 print("\tsupported options: %s", options2str(supported_options));
1227 missing_options = le32_to_cpu(rp->missing_options);
1228 print("\tmissing options: %s", options2str(missing_options));
1233 if (pending_index > 0)
1236 noninteractive_quit(EXIT_SUCCESS);
1239 static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param,
1242 const struct mgmt_rp_read_unconf_index_list *rp = param;
1247 error("Reading index list failed with status 0x%02x (%s)",
1248 status, mgmt_errstr(status));
1249 return noninteractive_quit(EXIT_FAILURE);
1252 if (len < sizeof(*rp)) {
1253 error("Too small index list reply (%u bytes)", len);
1254 return noninteractive_quit(EXIT_FAILURE);
1257 count = le16_to_cpu(rp->num_controllers);
1259 if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
1260 error("Index count (%u) doesn't match reply length (%u)",
1262 return noninteractive_quit(EXIT_FAILURE);
1265 print("Unconfigured index list with %u item%s",
1266 count, count != 1 ? "s" : "");
1268 for (i = 0; i < count; i++) {
1269 uint16_t index = le16_to_cpu(rp->index[i]);
1271 if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL,
1272 config_info_rsp, UINT_TO_PTR(index), NULL)) {
1273 error("Unable to send read_config_info cmd");
1274 return noninteractive_quit(EXIT_FAILURE);
1281 noninteractive_quit(EXIT_SUCCESS);
1284 static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1286 if (index == MGMT_INDEX_NONE) {
1287 if (!mgmt_send(mgmt, MGMT_OP_READ_UNCONF_INDEX_LIST,
1288 MGMT_INDEX_NONE, 0, NULL,
1289 unconf_index_rsp, mgmt, NULL)) {
1290 error("Unable to send unconf_index_list cmd");
1291 return noninteractive_quit(EXIT_FAILURE);
1297 if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL,
1298 config_info_rsp, UINT_TO_PTR(index), NULL)) {
1299 error("Unable to send read_config_info cmd");
1300 return noninteractive_quit(EXIT_FAILURE);
1304 static void config_options_rsp(uint8_t status, uint16_t len, const void *param,
1307 const struct mgmt_rp_read_config_info *rp = param;
1308 uint16_t index = PTR_TO_UINT(user_data);
1309 uint32_t supported_options, missing_options;
1312 error("Reading hci%u config failed with status 0x%02x (%s)",
1313 index, status, mgmt_errstr(status));
1317 if (len < sizeof(*rp)) {
1318 error("Too small info reply (%u bytes)", len);
1322 print("hci%u:\tConfiguration options", index);
1324 supported_options = le32_to_cpu(rp->supported_options);
1325 print("\tsupported options: %s", options2str(supported_options));
1327 missing_options = le32_to_cpu(rp->missing_options);
1328 print("\tmissing options: %s", options2str(missing_options));
1333 if (pending_index > 0)
1336 noninteractive_quit(EXIT_SUCCESS);
1339 static void info_rsp(uint8_t status, uint16_t len, const void *param,
1342 const struct mgmt_rp_read_info *rp = param;
1343 uint16_t index = PTR_TO_UINT(user_data);
1344 uint32_t supported_settings, current_settings;
1348 error("Reading hci%u info failed with status 0x%02x (%s)",
1349 index, status, mgmt_errstr(status));
1353 if (len < sizeof(*rp)) {
1354 error("Too small info reply (%u bytes)", len);
1358 print("hci%u:\tPrimary controller", index);
1360 ba2str(&rp->bdaddr, addr);
1361 print("\taddr %s version %u manufacturer %u class 0x%02x%02x%02x",
1362 addr, rp->version, le16_to_cpu(rp->manufacturer),
1363 rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
1365 supported_settings = le32_to_cpu(rp->supported_settings);
1366 print("\tsupported settings: %s", settings2str(supported_settings));
1368 current_settings = le32_to_cpu(rp->current_settings);
1369 print("\tcurrent settings: %s", settings2str(current_settings));
1371 print("\tname %s", rp->name);
1372 print("\tshort name %s", rp->short_name);
1374 if (supported_settings & MGMT_SETTING_CONFIGURATION) {
1375 if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO,
1376 index, 0, NULL, config_options_rsp,
1377 UINT_TO_PTR(index), NULL)) {
1378 error("Unable to send read_config cmd");
1387 if (pending_index > 0)
1390 noninteractive_quit(EXIT_SUCCESS);
1393 static void ext_info_rsp(uint8_t status, uint16_t len, const void *param,
1396 const struct mgmt_rp_read_ext_info *rp = param;
1397 uint16_t index = PTR_TO_UINT(user_data);
1398 uint32_t supported_settings, current_settings;
1402 error("Reading hci%u info failed with status 0x%02x (%s)",
1403 index, status, mgmt_errstr(status));
1407 if (len < sizeof(*rp)) {
1408 error("Too small info reply (%u bytes)", len);
1412 print("hci%u:\tPrimary controller", index);
1414 ba2str(&rp->bdaddr, addr);
1415 print("\taddr %s version %u manufacturer %u",
1416 addr, rp->version, le16_to_cpu(rp->manufacturer));
1418 supported_settings = le32_to_cpu(rp->supported_settings);
1419 print("\tsupported settings: %s", settings2str(supported_settings));
1421 current_settings = le32_to_cpu(rp->current_settings);
1422 print("\tcurrent settings: %s", settings2str(current_settings));
1424 if (supported_settings & MGMT_SETTING_CONFIGURATION) {
1425 if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO,
1426 index, 0, NULL, config_options_rsp,
1427 UINT_TO_PTR(index), NULL)) {
1428 error("Unable to send read_config cmd");
1437 if (pending_index > 0)
1440 noninteractive_quit(EXIT_SUCCESS);
1443 static void index_rsp(uint8_t status, uint16_t len, const void *param,
1446 const struct mgmt_rp_read_index_list *rp = param;
1447 struct mgmt *mgmt = user_data;
1452 error("Reading index list failed with status 0x%02x (%s)",
1453 status, mgmt_errstr(status));
1454 return noninteractive_quit(EXIT_FAILURE);
1457 if (len < sizeof(*rp)) {
1458 error("Too small index list reply (%u bytes)", len);
1459 return noninteractive_quit(EXIT_FAILURE);
1462 count = le16_to_cpu(rp->num_controllers);
1464 if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
1465 error("Index count (%u) doesn't match reply length (%u)",
1467 return noninteractive_quit(EXIT_FAILURE);
1470 print("Index list with %u item%s", count, count != 1 ? "s" : "");
1472 for (i = 0; i < count; i++) {
1473 uint16_t index = le16_to_cpu(rp->index[i]);
1475 if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
1476 info_rsp, UINT_TO_PTR(index), NULL)) {
1477 error("Unable to send read_info cmd");
1478 return noninteractive_quit(EXIT_FAILURE);
1485 noninteractive_quit(EXIT_SUCCESS);
1488 static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1490 if (index == MGMT_INDEX_NONE) {
1491 if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST,
1492 MGMT_INDEX_NONE, 0, NULL,
1493 index_rsp, mgmt, NULL)) {
1494 error("Unable to send index_list cmd");
1495 return noninteractive_quit(EXIT_FAILURE);
1501 if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, info_rsp,
1502 UINT_TO_PTR(index), NULL)) {
1503 error("Unable to send read_info cmd");
1504 return noninteractive_quit(EXIT_FAILURE);
1508 static void ext_index_rsp(uint8_t status, uint16_t len, const void *param,
1511 const struct mgmt_rp_read_ext_index_list *rp = param;
1512 uint16_t count, index_filter = PTR_TO_UINT(user_data);
1516 error("Reading ext index list failed with status 0x%02x (%s)",
1517 status, mgmt_errstr(status));
1518 return noninteractive_quit(EXIT_FAILURE);
1521 if (len < sizeof(*rp)) {
1522 error("Too small ext index list reply (%u bytes)", len);
1523 return noninteractive_quit(EXIT_FAILURE);
1526 count = get_le16(&rp->num_controllers);
1528 if (len < sizeof(*rp) + count * (sizeof(uint16_t) + sizeof(uint8_t))) {
1529 error("Index count (%u) doesn't match reply length (%u)",
1531 return noninteractive_quit(EXIT_FAILURE);
1534 print("Extended index list with %u item%s",
1535 count, count != 1 ? "s" : "");
1537 for (i = 0; i < count; i++) {
1538 uint16_t index = le16_to_cpu(rp->entry[i].index);
1539 char *busstr = hci_bustostr(rp->entry[i].bus);
1541 if (index_filter != MGMT_INDEX_NONE && index_filter != index)
1544 switch (rp->entry[i].type) {
1546 print("Primary controller (hci%u,%s)", index, busstr);
1547 if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INFO,
1548 index, 0, NULL, ext_info_rsp,
1549 UINT_TO_PTR(index), NULL)) {
1550 error("Unable to send read_ext_info cmd");
1551 return noninteractive_quit(EXIT_FAILURE);
1556 print("Unconfigured controller (hci%u,%s)",
1558 if (!mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO,
1559 index, 0, NULL, config_info_rsp,
1560 UINT_TO_PTR(index), NULL)) {
1561 error("Unable to send read_config cmd");
1562 return noninteractive_quit(EXIT_FAILURE);
1567 print("AMP controller (hci%u,%s)", index, busstr);
1570 print("Type %u controller (hci%u,%s)",
1571 rp->entry[i].type, index, busstr);
1579 noninteractive_quit(EXIT_SUCCESS);
1582 static void cmd_extinfo(struct mgmt *mgmt, uint16_t index,
1583 int argc, char **argv)
1585 if (!mgmt_send(mgmt, MGMT_OP_READ_EXT_INDEX_LIST,
1586 MGMT_INDEX_NONE, 0, NULL,
1587 ext_index_rsp, UINT_TO_PTR(index), NULL)) {
1588 error("Unable to send ext_index_list cmd");
1589 return noninteractive_quit(EXIT_FAILURE);
1593 static void auto_power_enable_rsp(uint8_t status, uint16_t len,
1594 const void *param, void *user_data)
1596 uint16_t index = PTR_TO_UINT(user_data);
1598 print("Successfully enabled controller with index %u", index);
1600 noninteractive_quit(EXIT_SUCCESS);
1603 static void auto_power_info_rsp(uint8_t status, uint16_t len,
1604 const void *param, void *user_data)
1606 const struct mgmt_rp_read_info *rp = param;
1607 uint16_t index = PTR_TO_UINT(user_data);
1608 uint32_t supported_settings, current_settings, missing_settings;
1612 error("Reading info failed with status 0x%02x (%s)",
1613 status, mgmt_errstr(status));
1614 return noninteractive_quit(EXIT_FAILURE);
1617 supported_settings = le32_to_cpu(rp->supported_settings);
1618 current_settings = le32_to_cpu(rp->current_settings);
1619 missing_settings = current_settings ^ supported_settings;
1621 if (missing_settings & MGMT_SETTING_BREDR)
1622 mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, sizeof(val), &val,
1625 if (missing_settings & MGMT_SETTING_SSP)
1626 mgmt_send(mgmt, MGMT_OP_SET_SSP, index, sizeof(val), &val,
1629 if (missing_settings & MGMT_SETTING_LE)
1630 mgmt_send(mgmt, MGMT_OP_SET_LE, index, sizeof(val), &val,
1633 if (missing_settings & MGMT_SETTING_SECURE_CONN)
1634 mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index,
1638 if (missing_settings & MGMT_SETTING_BONDABLE)
1639 mgmt_send(mgmt, MGMT_OP_SET_BONDABLE, index, sizeof(val), &val,
1642 if (current_settings & MGMT_SETTING_POWERED)
1643 return noninteractive_quit(EXIT_SUCCESS);
1645 if (!mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, sizeof(val), &val,
1646 auto_power_enable_rsp,
1647 UINT_TO_PTR(index), NULL)) {
1648 error("Unable to send set powerd cmd");
1649 return noninteractive_quit(EXIT_FAILURE);
1653 static void auto_power_index_evt(uint16_t index, uint16_t len,
1654 const void *param, void *user_data)
1656 uint16_t index_filter = PTR_TO_UINT(user_data);
1658 if (index != index_filter)
1661 print("New controller with index %u", index);
1663 if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
1664 auto_power_info_rsp,
1665 UINT_TO_PTR(index), NULL)) {
1666 error("Unable to send read info cmd");
1667 return noninteractive_quit(EXIT_FAILURE);
1671 static void auto_power_index_rsp(uint8_t status, uint16_t len,
1672 const void *param, void *user_data)
1674 const struct mgmt_rp_read_index_list *rp = param;
1675 uint16_t index = PTR_TO_UINT(user_data);
1680 error("Reading index list failed with status 0x%02x (%s)",
1681 status, mgmt_errstr(status));
1682 return noninteractive_quit(EXIT_FAILURE);
1685 count = le16_to_cpu(rp->num_controllers);
1686 for (i = 0; i < count; i++) {
1687 if (le16_to_cpu(rp->index[i]) == index)
1692 print("Waiting for index %u to appear", index);
1694 mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index,
1695 auto_power_index_evt,
1696 UINT_TO_PTR(index), NULL);
1700 print("Found controller with index %u", index);
1702 if (!mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
1703 auto_power_info_rsp,
1704 UINT_TO_PTR(index), NULL)) {
1705 error("Unable to send read info cmd");
1706 return noninteractive_quit(EXIT_FAILURE);
1710 static void cmd_auto_power(struct mgmt *mgmt, uint16_t index,
1711 int argc, char **argv)
1713 if (index == MGMT_INDEX_NONE)
1716 if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
1717 auto_power_index_rsp,
1718 UINT_TO_PTR(index), NULL)) {
1719 error("Unable to send read index list cmd");
1720 return noninteractive_quit(EXIT_FAILURE);
1724 /* Wrapper to get the index and opcode to the response callback */
1725 struct command_data {
1728 void (*callback) (uint16_t id, uint16_t op, uint8_t status,
1729 uint16_t len, const void *param);
1732 static void cmd_rsp(uint8_t status, uint16_t len, const void *param,
1735 struct command_data *data = user_data;
1737 data->callback(data->op, data->id, status, len, param);
1740 static unsigned int send_cmd(struct mgmt *mgmt, uint16_t op, uint16_t id,
1741 uint16_t len, const void *param,
1742 void (*cb)(uint16_t id, uint16_t op,
1743 uint8_t status, uint16_t len,
1746 struct command_data *data;
1747 unsigned int send_id;
1749 data = new0(struct command_data, 1);
1755 data->callback = cb;
1757 send_id = mgmt_send(mgmt, op, id, len, param, cmd_rsp, data, free);
1764 static void setting_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
1767 const uint32_t *rp = param;
1770 error("%s for hci%u failed with status 0x%02x (%s)",
1771 mgmt_opstr(op), id, status, mgmt_errstr(status));
1775 if (len < sizeof(*rp)) {
1776 error("Too small %s response (%u bytes)",
1777 mgmt_opstr(op), len);
1781 print("hci%u %s complete, settings: %s", id, mgmt_opstr(op),
1782 settings2str(get_le32(rp)));
1785 noninteractive_quit(EXIT_SUCCESS);
1788 static void cmd_setting(struct mgmt *mgmt, uint16_t index, uint16_t op,
1789 int argc, char **argv)
1794 print("Specify \"on\" or \"off\"");
1795 return noninteractive_quit(EXIT_FAILURE);
1798 if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
1800 else if (strcasecmp(argv[1], "off") == 0)
1803 val = atoi(argv[1]);
1805 if (index == MGMT_INDEX_NONE)
1808 if (send_cmd(mgmt, op, index, sizeof(val), &val, setting_rsp) == 0) {
1809 error("Unable to send %s cmd", mgmt_opstr(op));
1810 return noninteractive_quit(EXIT_FAILURE);
1814 static void cmd_power(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1816 cmd_setting(mgmt, index, MGMT_OP_SET_POWERED, argc, argv);
1819 static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc,
1822 struct mgmt_cp_set_discoverable cp;
1825 print("Usage: %s <yes/no/limited> [timeout]", argv[0]);
1826 return noninteractive_quit(EXIT_FAILURE);
1829 memset(&cp, 0, sizeof(cp));
1831 if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
1833 else if (strcasecmp(argv[1], "off") == 0)
1835 else if (strcasecmp(argv[1], "limited") == 0)
1838 cp.val = atoi(argv[1]);
1841 cp.timeout = htobs(atoi(argv[2]));
1843 if (index == MGMT_INDEX_NONE)
1846 if (send_cmd(mgmt, MGMT_OP_SET_DISCOVERABLE, index, sizeof(cp), &cp,
1847 setting_rsp) == 0) {
1848 error("Unable to send set_discoverable cmd");
1849 return noninteractive_quit(EXIT_FAILURE);
1853 static void cmd_connectable(struct mgmt *mgmt, uint16_t index, int argc,
1856 cmd_setting(mgmt, index, MGMT_OP_SET_CONNECTABLE, argc, argv);
1859 static void cmd_fast_conn(struct mgmt *mgmt, uint16_t index, int argc,
1862 cmd_setting(mgmt, index, MGMT_OP_SET_FAST_CONNECTABLE, argc, argv);
1865 static void cmd_bondable(struct mgmt *mgmt, uint16_t index, int argc,
1868 cmd_setting(mgmt, index, MGMT_OP_SET_BONDABLE, argc, argv);
1871 static void cmd_linksec(struct mgmt *mgmt, uint16_t index, int argc,
1874 cmd_setting(mgmt, index, MGMT_OP_SET_LINK_SECURITY, argc, argv);
1877 static void cmd_ssp(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1879 cmd_setting(mgmt, index, MGMT_OP_SET_SSP, argc, argv);
1882 static void cmd_sc(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1887 print("Specify \"on\" or \"off\" or \"only\"");
1888 return noninteractive_quit(EXIT_FAILURE);
1891 if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
1893 else if (strcasecmp(argv[1], "off") == 0)
1895 else if (strcasecmp(argv[1], "only") == 0)
1898 val = atoi(argv[1]);
1900 if (index == MGMT_INDEX_NONE)
1903 if (send_cmd(mgmt, MGMT_OP_SET_SECURE_CONN, index,
1904 sizeof(val), &val, setting_rsp) == 0) {
1905 error("Unable to send set_secure_conn cmd");
1906 return noninteractive_quit(EXIT_FAILURE);
1910 static void cmd_hs(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1912 cmd_setting(mgmt, index, MGMT_OP_SET_HS, argc, argv);
1915 static void cmd_le(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1917 cmd_setting(mgmt, index, MGMT_OP_SET_LE, argc, argv);
1920 static void cmd_advertising(struct mgmt *mgmt, uint16_t index, int argc,
1923 cmd_setting(mgmt, index, MGMT_OP_SET_ADVERTISING, argc, argv);
1926 static void cmd_bredr(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
1928 cmd_setting(mgmt, index, MGMT_OP_SET_BREDR, argc, argv);
1931 static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc,
1934 struct mgmt_cp_set_privacy cp;
1937 print("Specify \"on\" or \"off\"");
1938 return noninteractive_quit(EXIT_FAILURE);
1941 if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
1943 else if (strcasecmp(argv[1], "off") == 0)
1946 cp.privacy = atoi(argv[1]);
1948 if (index == MGMT_INDEX_NONE)
1952 if (hex2bin(argv[2], cp.irk,
1953 sizeof(cp.irk)) != sizeof(cp.irk)) {
1954 error("Invalid key format");
1955 return noninteractive_quit(EXIT_FAILURE);
1960 fd = open("/dev/urandom", O_RDONLY);
1962 error("open(/dev/urandom): %s", strerror(errno));
1963 return noninteractive_quit(EXIT_FAILURE);
1966 if (read(fd, cp.irk, sizeof(cp.irk)) != sizeof(cp.irk)) {
1967 error("Reading from urandom failed");
1969 return noninteractive_quit(EXIT_FAILURE);
1975 if (send_cmd(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp,
1976 setting_rsp) == 0) {
1977 error("Unable to send Set Privacy command");
1978 return noninteractive_quit(EXIT_FAILURE);
1982 static void class_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
1985 const struct mgmt_ev_class_of_dev_changed *rp = param;
1987 if (len == 0 && status != 0) {
1988 error("%s failed, status 0x%02x (%s)",
1989 mgmt_opstr(op), status, mgmt_errstr(status));
1990 return noninteractive_quit(EXIT_FAILURE);
1993 if (len != sizeof(*rp)) {
1994 error("Unexpected %s len %u", mgmt_opstr(op), len);
1995 return noninteractive_quit(EXIT_FAILURE);
1998 print("%s succeeded. Class 0x%02x%02x%02x", mgmt_opstr(op),
1999 rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
2001 noninteractive_quit(EXIT_SUCCESS);
2004 static void cmd_class(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2009 print("Usage: %s <major> <minor>", argv[0]);
2010 return noninteractive_quit(EXIT_FAILURE);
2013 class[0] = atoi(argv[1]);
2014 class[1] = atoi(argv[2]);
2016 if (index == MGMT_INDEX_NONE)
2019 if (send_cmd(mgmt, MGMT_OP_SET_DEV_CLASS, index, sizeof(class), class,
2021 error("Unable to send set_dev_class cmd");
2022 return noninteractive_quit(EXIT_FAILURE);
2026 static void disconnect_rsp(uint8_t status, uint16_t len, const void *param,
2029 const struct mgmt_rp_disconnect *rp = param;
2032 if (len == 0 && status != 0) {
2033 error("Disconnect failed with status 0x%02x (%s)",
2034 status, mgmt_errstr(status));
2035 return noninteractive_quit(EXIT_FAILURE);
2038 if (len != sizeof(*rp)) {
2039 error("Invalid disconnect response length (%u)", len);
2040 return noninteractive_quit(EXIT_FAILURE);
2043 ba2str(&rp->addr.bdaddr, addr);
2046 print("%s disconnected", addr);
2048 error("Disconnecting %s failed with status 0x%02x (%s)",
2049 addr, status, mgmt_errstr(status));
2051 noninteractive_quit(EXIT_SUCCESS);
2054 static void disconnect_usage(void)
2056 print("Usage: disconnect [-t type] <remote address>");
2059 static struct option disconnect_options[] = {
2060 { "help", 0, 0, 'h' },
2061 { "type", 1, 0, 't' },
2065 static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc,
2068 struct mgmt_cp_disconnect cp;
2069 uint8_t type = BDADDR_BREDR;
2072 while ((opt = getopt_long(argc, argv, "+t:h", disconnect_options,
2076 type = strtol(optarg, NULL, 0);
2081 return noninteractive_quit(EXIT_SUCCESS);
2085 return noninteractive_quit(EXIT_FAILURE);
2095 return noninteractive_quit(EXIT_FAILURE);
2098 if (index == MGMT_INDEX_NONE)
2101 memset(&cp, 0, sizeof(cp));
2102 str2ba(argv[0], &cp.addr.bdaddr);
2103 cp.addr.type = type;
2105 if (mgmt_send(mgmt, MGMT_OP_DISCONNECT, index, sizeof(cp), &cp,
2106 disconnect_rsp, NULL, NULL) == 0) {
2107 error("Unable to send disconnect cmd");
2108 return noninteractive_quit(EXIT_FAILURE);
2112 static void con_rsp(uint8_t status, uint16_t len, const void *param,
2115 const struct mgmt_rp_get_connections *rp = param;
2118 if (len < sizeof(*rp)) {
2119 error("Too small (%u bytes) get_connections rsp", len);
2120 return noninteractive_quit(EXIT_FAILURE);
2123 count = get_le16(&rp->conn_count);
2124 if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) {
2125 error("Invalid get_connections length (count=%u, len=%u)",
2127 return noninteractive_quit(EXIT_FAILURE);
2130 for (i = 0; i < count; i++) {
2133 ba2str(&rp->addr[i].bdaddr, addr);
2135 print("%s type %s", addr, typestr(rp->addr[i].type));
2138 noninteractive_quit(EXIT_SUCCESS);
2141 static void cmd_con(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2143 if (index == MGMT_INDEX_NONE)
2146 if (mgmt_send(mgmt, MGMT_OP_GET_CONNECTIONS, index, 0, NULL,
2147 con_rsp, NULL, NULL) == 0) {
2148 error("Unable to send get_connections cmd");
2149 return noninteractive_quit(EXIT_FAILURE);
2153 static void find_service_rsp(uint8_t status, uint16_t len, const void *param,
2157 error("Start Service Discovery failed: status 0x%02x (%s)",
2158 status, mgmt_errstr(status));
2159 return noninteractive_quit(EXIT_FAILURE);
2162 print("Service discovery started");
2166 static void find_service_usage(void)
2168 print("Usage: find-service [-u UUID] [-r RSSI_Threshold] [-l|-b]");
2171 static struct option find_service_options[] = {
2172 { "help", no_argument, 0, 'h' },
2173 { "le-only", no_argument, 0, 'l' },
2174 { "bredr-only", no_argument, 0, 'b' },
2175 { "uuid", required_argument, 0, 'u' },
2176 { "rssi", required_argument, 0, 'r' },
2180 static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
2182 if (uuid->type == SDP_UUID16)
2183 sdp_uuid16_to_uuid128(uuid128, uuid);
2184 else if (uuid->type == SDP_UUID32)
2185 sdp_uuid32_to_uuid128(uuid128, uuid);
2187 memcpy(uuid128, uuid, sizeof(*uuid));
2192 static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
2195 struct mgmt_cp_start_service_discovery *cp;
2196 uint8_t buf[sizeof(*cp) + 16 * MAX_UUIDS];
2200 uint8_t type = SCAN_TYPE_DUAL;
2205 if (index == MGMT_INDEX_NONE)
2212 find_service_usage();
2213 return noninteractive_quit(EXIT_FAILURE);
2216 while ((opt = getopt_long(argc, argv, "+lbu:r:p:h",
2217 find_service_options, NULL)) != -1) {
2220 type &= ~SCAN_TYPE_BREDR;
2221 type |= SCAN_TYPE_LE;
2224 type |= SCAN_TYPE_BREDR;
2225 type &= ~SCAN_TYPE_LE;
2228 if (count == MAX_UUIDS) {
2229 print("Max %u UUIDs supported", MAX_UUIDS);
2231 return noninteractive_quit(EXIT_FAILURE);
2234 if (bt_string2uuid(&uuid, optarg) < 0) {
2235 print("Invalid UUID: %s", optarg);
2237 return noninteractive_quit(EXIT_FAILURE);
2240 uuid_to_uuid128(&uuid128, &uuid);
2241 ntoh128((uint128_t *) uuid128.value.uuid128.data,
2243 htob128(&uint128, (uint128_t *) cp->uuids[count++]);
2246 rssi = atoi(optarg);
2249 find_service_usage();
2251 return noninteractive_quit(EXIT_SUCCESS);
2253 find_service_usage();
2255 return noninteractive_quit(EXIT_FAILURE);
2264 find_service_usage();
2265 return noninteractive_quit(EXIT_FAILURE);
2271 cp->uuid_count = cpu_to_le16(count);
2273 if (mgmt_send(mgmt, MGMT_OP_START_SERVICE_DISCOVERY, index,
2274 sizeof(*cp) + count * 16, cp,
2275 find_service_rsp, NULL, NULL) == 0) {
2276 error("Unable to send start_service_discovery cmd");
2277 return noninteractive_quit(EXIT_FAILURE);
2281 static void find_rsp(uint8_t status, uint16_t len, const void *param,
2285 error("Unable to start discovery. status 0x%02x (%s)",
2286 status, mgmt_errstr(status));
2287 return noninteractive_quit(EXIT_FAILURE);
2290 print("Discovery started");
2294 static void find_usage(void)
2296 print("Usage: find [-l|-b]>");
2299 static struct option find_options[] = {
2300 { "help", 0, 0, 'h' },
2301 { "le-only", 1, 0, 'l' },
2302 { "bredr-only", 1, 0, 'b' },
2303 { "limited", 1, 0, 'L' },
2307 static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2309 struct mgmt_cp_start_discovery cp;
2310 uint8_t op = MGMT_OP_START_DISCOVERY;
2311 uint8_t type = SCAN_TYPE_DUAL;
2314 if (index == MGMT_INDEX_NONE)
2317 while ((opt = getopt_long(argc, argv, "+lbLh", find_options,
2321 type &= ~SCAN_TYPE_BREDR;
2322 type |= SCAN_TYPE_LE;
2325 type |= SCAN_TYPE_BREDR;
2326 type &= ~SCAN_TYPE_LE;
2329 op = MGMT_OP_START_LIMITED_DISCOVERY;
2334 return noninteractive_quit(EXIT_SUCCESS);
2338 return noninteractive_quit(EXIT_FAILURE);
2346 memset(&cp, 0, sizeof(cp));
2349 if (mgmt_send(mgmt, op, index, sizeof(cp), &cp, find_rsp,
2351 error("Unable to send start_discovery cmd");
2352 return noninteractive_quit(EXIT_FAILURE);
2356 static void stop_find_rsp(uint8_t status, uint16_t len, const void *param,
2361 "Stop Discovery failed: status 0x%02x (%s)\n",
2362 status, mgmt_errstr(status));
2363 return noninteractive_quit(EXIT_SUCCESS);
2366 printf("Discovery stopped\n");
2369 noninteractive_quit(EXIT_SUCCESS);
2372 static void stop_find_usage(void)
2374 printf("Usage: btmgmt stop-find [-l|-b]>\n");
2377 static struct option stop_find_options[] = {
2378 { "help", 0, 0, 'h' },
2379 { "le-only", 1, 0, 'l' },
2380 { "bredr-only", 1, 0, 'b' },
2384 static void cmd_stop_find(struct mgmt *mgmt, uint16_t index, int argc,
2387 struct mgmt_cp_stop_discovery cp;
2388 uint8_t type = SCAN_TYPE_DUAL;
2391 if (index == MGMT_INDEX_NONE)
2394 while ((opt = getopt_long(argc, argv, "+lbh", stop_find_options,
2398 type &= ~SCAN_TYPE_BREDR;
2399 type |= SCAN_TYPE_LE;
2402 type |= SCAN_TYPE_BREDR;
2403 type &= ~SCAN_TYPE_LE;
2417 memset(&cp, 0, sizeof(cp));
2420 if (mgmt_send(mgmt, MGMT_OP_STOP_DISCOVERY, index, sizeof(cp), &cp,
2421 stop_find_rsp, NULL, NULL) == 0) {
2422 fprintf(stderr, "Unable to send stop_discovery cmd\n");
2427 static void name_rsp(uint8_t status, uint16_t len, const void *param,
2431 error("Unable to set local name with status 0x%02x (%s)",
2432 status, mgmt_errstr(status));
2434 noninteractive_quit(EXIT_SUCCESS);
2437 static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2439 struct mgmt_cp_set_local_name cp;
2442 print("Usage: %s <name> [shortname]", argv[0]);
2443 return noninteractive_quit(EXIT_FAILURE);
2446 if (index == MGMT_INDEX_NONE)
2449 memset(&cp, 0, sizeof(cp));
2450 strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH);
2452 strncpy((char *) cp.short_name, argv[2],
2453 MGMT_MAX_SHORT_NAME_LENGTH);
2455 if (mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, index, sizeof(cp), &cp,
2456 name_rsp, NULL, NULL) == 0) {
2457 error("Unable to send set_name cmd");
2458 return noninteractive_quit(EXIT_FAILURE);
2462 static void pair_rsp(uint8_t status, uint16_t len, const void *param,
2465 const struct mgmt_rp_pair_device *rp = param;
2468 if (len == 0 && status != 0) {
2469 error("Pairing failed with status 0x%02x (%s)",
2470 status, mgmt_errstr(status));
2471 return noninteractive_quit(EXIT_FAILURE);
2474 if (len != sizeof(*rp)) {
2475 error("Unexpected pair_rsp len %u", len);
2476 return noninteractive_quit(EXIT_FAILURE);
2479 if (!memcmp(&rp->addr, &prompt.addr, sizeof(rp->addr)))
2482 ba2str(&rp->addr.bdaddr, addr);
2485 error("Pairing with %s (%s) failed. status 0x%02x (%s)",
2486 addr, typestr(rp->addr.type), status,
2487 mgmt_errstr(status));
2489 print("Paired with %s (%s)", addr, typestr(rp->addr.type));
2491 noninteractive_quit(EXIT_SUCCESS);
2494 static void pair_usage(void)
2496 print("Usage: pair [-c cap] [-t type] <remote address>");
2499 static struct option pair_options[] = {
2500 { "help", 0, 0, 'h' },
2501 { "capability", 1, 0, 'c' },
2502 { "type", 1, 0, 't' },
2506 static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2508 struct mgmt_cp_pair_device cp;
2510 uint8_t type = BDADDR_BREDR;
2514 while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options,
2518 cap = strtol(optarg, NULL, 0);
2521 type = strtol(optarg, NULL, 0);
2526 return noninteractive_quit(EXIT_SUCCESS);
2530 return noninteractive_quit(EXIT_FAILURE);
2540 return noninteractive_quit(EXIT_FAILURE);
2543 if (index == MGMT_INDEX_NONE)
2546 memset(&cp, 0, sizeof(cp));
2547 str2ba(argv[0], &cp.addr.bdaddr);
2548 cp.addr.type = type;
2551 ba2str(&cp.addr.bdaddr, addr);
2552 print("Pairing with %s (%s)", addr, typestr(cp.addr.type));
2554 if (mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp,
2555 pair_rsp, NULL, NULL) == 0) {
2556 error("Unable to send pair_device cmd");
2557 return noninteractive_quit(EXIT_FAILURE);
2561 static void cancel_pair_rsp(uint8_t status, uint16_t len, const void *param,
2564 const struct mgmt_addr_info *rp = param;
2567 if (len == 0 && status != 0) {
2568 error("Cancel Pairing failed with 0x%02x (%s)",
2569 status, mgmt_errstr(status));
2570 return noninteractive_quit(EXIT_FAILURE);
2573 if (len != sizeof(*rp)) {
2574 error("Unexpected cancel_pair_rsp len %u", len);
2575 return noninteractive_quit(EXIT_FAILURE);
2578 ba2str(&rp->bdaddr, addr);
2581 error("Cancel Pairing with %s (%s) failed. 0x%02x (%s)",
2582 addr, typestr(rp->type), status,
2583 mgmt_errstr(status));
2585 print("Pairing Cancelled with %s", addr);
2587 noninteractive_quit(EXIT_SUCCESS);
2590 static void cancel_pair_usage(void)
2592 print("Usage: cancelpair [-t type] <remote address>");
2595 static struct option cancel_pair_options[] = {
2596 { "help", 0, 0, 'h' },
2597 { "type", 1, 0, 't' },
2601 static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc,
2604 struct mgmt_addr_info cp;
2605 uint8_t type = BDADDR_BREDR;
2608 while ((opt = getopt_long(argc, argv, "+t:h", cancel_pair_options,
2612 type = strtol(optarg, NULL, 0);
2615 cancel_pair_usage();
2617 return noninteractive_quit(EXIT_SUCCESS);
2619 cancel_pair_usage();
2621 return noninteractive_quit(EXIT_FAILURE);
2630 cancel_pair_usage();
2631 return noninteractive_quit(EXIT_FAILURE);
2634 if (index == MGMT_INDEX_NONE)
2637 memset(&cp, 0, sizeof(cp));
2638 str2ba(argv[0], &cp.bdaddr);
2641 if (mgmt_reply(mgmt, MGMT_OP_CANCEL_PAIR_DEVICE, index, sizeof(cp), &cp,
2642 cancel_pair_rsp, NULL, NULL) == 0) {
2643 error("Unable to send cancel_pair_device cmd");
2644 return noninteractive_quit(EXIT_FAILURE);
2648 static void unpair_rsp(uint8_t status, uint16_t len, const void *param,
2651 const struct mgmt_rp_unpair_device *rp = param;
2654 if (len == 0 && status != 0) {
2655 error("Unpair device failed. status 0x%02x (%s)",
2656 status, mgmt_errstr(status));
2657 return noninteractive_quit(EXIT_FAILURE);
2660 if (len != sizeof(*rp)) {
2661 error("Unexpected unpair_device_rsp len %u", len);
2662 return noninteractive_quit(EXIT_FAILURE);
2665 ba2str(&rp->addr.bdaddr, addr);
2668 error("Unpairing %s failed. status 0x%02x (%s)",
2669 addr, status, mgmt_errstr(status));
2671 print("%s unpaired", addr);
2673 noninteractive_quit(EXIT_SUCCESS);
2676 static void unpair_usage(void)
2678 print("Usage: unpair [-t type] <remote address>");
2681 static struct option unpair_options[] = {
2682 { "help", 0, 0, 'h' },
2683 { "type", 1, 0, 't' },
2687 static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc,
2690 struct mgmt_cp_unpair_device cp;
2691 uint8_t type = BDADDR_BREDR;
2694 while ((opt = getopt_long(argc, argv, "+t:h", unpair_options,
2698 type = strtol(optarg, NULL, 0);
2703 return noninteractive_quit(EXIT_SUCCESS);
2707 return noninteractive_quit(EXIT_FAILURE);
2717 return noninteractive_quit(EXIT_FAILURE);
2720 if (index == MGMT_INDEX_NONE)
2723 memset(&cp, 0, sizeof(cp));
2724 str2ba(argv[0], &cp.addr.bdaddr);
2725 cp.addr.type = type;
2728 if (mgmt_send(mgmt, MGMT_OP_UNPAIR_DEVICE, index, sizeof(cp), &cp,
2729 unpair_rsp, NULL, NULL) == 0) {
2730 error("Unable to send unpair_device cmd");
2731 return noninteractive_quit(EXIT_FAILURE);
2735 static void keys_rsp(uint8_t status, uint16_t len, const void *param,
2739 error("Load keys failed with status 0x%02x (%s)",
2740 status, mgmt_errstr(status));
2742 print("Keys successfully loaded");
2744 noninteractive_quit(EXIT_SUCCESS);
2747 static void cmd_keys(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2749 struct mgmt_cp_load_link_keys cp;
2751 if (index == MGMT_INDEX_NONE)
2754 memset(&cp, 0, sizeof(cp));
2756 if (mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index, sizeof(cp), &cp,
2757 keys_rsp, NULL, NULL) == 0) {
2758 error("Unable to send load_keys cmd");
2759 return noninteractive_quit(EXIT_FAILURE);
2763 static void ltks_rsp(uint8_t status, uint16_t len, const void *param,
2767 error("Load keys failed with status 0x%02x (%s)",
2768 status, mgmt_errstr(status));
2770 print("Long term keys successfully loaded");
2772 noninteractive_quit(EXIT_SUCCESS);
2775 static void cmd_ltks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2777 struct mgmt_cp_load_long_term_keys cp;
2779 if (index == MGMT_INDEX_NONE)
2782 memset(&cp, 0, sizeof(cp));
2784 if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index, sizeof(cp), &cp,
2785 ltks_rsp, NULL, NULL) == 0) {
2786 error("Unable to send load_ltks cmd");
2787 return noninteractive_quit(EXIT_SUCCESS);
2791 static void irks_rsp(uint8_t status, uint16_t len, const void *param,
2795 error("Load IRKs failed with status 0x%02x (%s)",
2796 status, mgmt_errstr(status));
2798 print("Identity Resolving Keys successfully loaded");
2800 noninteractive_quit(EXIT_SUCCESS);
2803 static void irks_usage(void)
2805 print("Usage: irks [--local]");
2808 static struct option irks_options[] = {
2809 { "help", 0, 0, 'h' },
2810 { "local", 1, 0, 'l' },
2811 { "file", 1, 0, 'f' },
2817 static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2819 struct mgmt_cp_load_irks *cp;
2820 uint8_t buf[sizeof(*cp) + 23 * MAX_IRKS];
2821 uint16_t count, local_index;
2822 char path[PATH_MAX];
2825 if (index == MGMT_INDEX_NONE)
2831 while ((opt = getopt_long(argc, argv, "+l:f:h",
2832 irks_options, NULL)) != -1) {
2835 if (count >= MAX_IRKS) {
2836 error("Number of IRKs exceeded");
2838 return noninteractive_quit(EXIT_FAILURE);
2840 if (strlen(optarg) > 3 &&
2841 strncasecmp(optarg, "hci", 3) == 0)
2842 local_index = atoi(optarg + 3);
2844 local_index = atoi(optarg);
2845 snprintf(path, sizeof(path),
2846 "/sys/kernel/debug/bluetooth/hci%u/identity",
2848 if (!load_identity(path, &cp->irks[count])) {
2849 error("Unable to load identity");
2851 return noninteractive_quit(EXIT_FAILURE);
2856 if (count >= MAX_IRKS) {
2857 error("Number of IRKs exceeded");
2859 return noninteractive_quit(EXIT_FAILURE);
2861 if (!load_identity(optarg, &cp->irks[count])) {
2862 error("Unable to load identities");
2864 return noninteractive_quit(EXIT_FAILURE);
2871 return noninteractive_quit(EXIT_SUCCESS);
2875 return noninteractive_quit(EXIT_FAILURE);
2885 return noninteractive_quit(EXIT_FAILURE);
2888 cp->irk_count = cpu_to_le16(count);
2890 if (mgmt_send(mgmt, MGMT_OP_LOAD_IRKS, index,
2891 sizeof(*cp) + count * 23, cp,
2892 irks_rsp, NULL, NULL) == 0) {
2893 error("Unable to send load_irks cmd");
2894 return noninteractive_quit(EXIT_FAILURE);
2898 static void block_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
2901 const struct mgmt_addr_info *rp = param;
2904 if (len == 0 && status != 0) {
2905 error("%s failed, status 0x%02x (%s)",
2906 mgmt_opstr(op), status, mgmt_errstr(status));
2907 return noninteractive_quit(EXIT_FAILURE);
2910 if (len != sizeof(*rp)) {
2911 error("Unexpected %s len %u", mgmt_opstr(op), len);
2912 return noninteractive_quit(EXIT_FAILURE);
2915 ba2str(&rp->bdaddr, addr);
2918 error("%s %s (%s) failed. status 0x%02x (%s)",
2919 mgmt_opstr(op), addr, typestr(rp->type),
2920 status, mgmt_errstr(status));
2922 print("%s %s succeeded", mgmt_opstr(op), addr);
2924 noninteractive_quit(EXIT_SUCCESS);
2927 static void block_usage(void)
2929 print("Usage: block [-t type] <remote address>");
2932 static struct option block_options[] = {
2933 { "help", 0, 0, 'h' },
2934 { "type", 1, 0, 't' },
2938 static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
2940 struct mgmt_cp_block_device cp;
2941 uint8_t type = BDADDR_BREDR;
2944 while ((opt = getopt_long(argc, argv, "+t:h", block_options,
2948 type = strtol(optarg, NULL, 0);
2953 return noninteractive_quit(EXIT_SUCCESS);
2957 return noninteractive_quit(EXIT_FAILURE);
2967 return noninteractive_quit(EXIT_FAILURE);
2970 if (index == MGMT_INDEX_NONE)
2973 memset(&cp, 0, sizeof(cp));
2974 str2ba(argv[0], &cp.addr.bdaddr);
2975 cp.addr.type = type;
2977 if (send_cmd(mgmt, MGMT_OP_BLOCK_DEVICE, index, sizeof(cp), &cp,
2979 error("Unable to send block_device cmd");
2980 return noninteractive_quit(EXIT_FAILURE);
2984 static void unblock_usage(void)
2986 print("Usage: unblock [-t type] <remote address>");
2989 static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
2992 struct mgmt_cp_unblock_device cp;
2993 uint8_t type = BDADDR_BREDR;
2996 while ((opt = getopt_long(argc, argv, "+t:h", block_options,
3000 type = strtol(optarg, NULL, 0);
3005 return noninteractive_quit(EXIT_SUCCESS);
3009 return noninteractive_quit(EXIT_FAILURE);
3019 return noninteractive_quit(EXIT_FAILURE);
3022 if (index == MGMT_INDEX_NONE)
3025 memset(&cp, 0, sizeof(cp));
3026 str2ba(argv[0], &cp.addr.bdaddr);
3027 cp.addr.type = type;
3029 if (send_cmd(mgmt, MGMT_OP_UNBLOCK_DEVICE, index, sizeof(cp), &cp,
3031 error("Unable to send unblock_device cmd");
3032 return noninteractive_quit(EXIT_FAILURE);
3036 static void cmd_add_uuid(struct mgmt *mgmt, uint16_t index, int argc,
3039 struct mgmt_cp_add_uuid cp;
3041 uuid_t uuid, uuid128;
3044 print("UUID and service hint needed");
3045 return noninteractive_quit(EXIT_FAILURE);
3048 if (index == MGMT_INDEX_NONE)
3051 if (bt_string2uuid(&uuid, argv[1]) < 0) {
3052 print("Invalid UUID: %s", argv[1]);
3053 return noninteractive_quit(EXIT_FAILURE);
3056 memset(&cp, 0, sizeof(cp));
3058 uuid_to_uuid128(&uuid128, &uuid);
3059 ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
3060 htob128(&uint128, (uint128_t *) cp.uuid);
3062 cp.svc_hint = atoi(argv[2]);
3064 if (send_cmd(mgmt, MGMT_OP_ADD_UUID, index, sizeof(cp), &cp,
3066 error("Unable to send add_uuid cmd");
3067 return noninteractive_quit(EXIT_FAILURE);
3071 static void cmd_remove_uuid(struct mgmt *mgmt, uint16_t index, int argc,
3074 struct mgmt_cp_remove_uuid cp;
3076 uuid_t uuid, uuid128;
3079 print("UUID needed");
3080 return noninteractive_quit(EXIT_FAILURE);
3083 if (index == MGMT_INDEX_NONE)
3086 if (bt_string2uuid(&uuid, argv[1]) < 0) {
3087 print("Invalid UUID: %s", argv[1]);
3088 return noninteractive_quit(EXIT_FAILURE);
3091 memset(&cp, 0, sizeof(cp));
3093 uuid_to_uuid128(&uuid128, &uuid);
3094 ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
3095 htob128(&uint128, (uint128_t *) cp.uuid);
3097 if (send_cmd(mgmt, MGMT_OP_REMOVE_UUID, index, sizeof(cp), &cp,
3099 error("Unable to send remove_uuid cmd");
3100 return noninteractive_quit(EXIT_FAILURE);
3104 static void cmd_clr_uuids(struct mgmt *mgmt, uint16_t index, int argc,
3107 char *uuid_any = "00000000-0000-0000-0000-000000000000";
3108 char *rm_argv[] = { "rm-uuid", uuid_any, NULL };
3110 cmd_remove_uuid(mgmt, index, 2, rm_argv);
3113 static void local_oob_rsp(uint8_t status, uint16_t len, const void *param,
3116 const struct mgmt_rp_read_local_oob_data *rp = param;
3120 error("Read Local OOB Data failed with status 0x%02x (%s)",
3121 status, mgmt_errstr(status));
3122 return noninteractive_quit(EXIT_FAILURE);
3125 if (len < sizeof(*rp)) {
3126 error("Too small (%u bytes) read_local_oob rsp", len);
3127 return noninteractive_quit(EXIT_FAILURE);
3130 bin2hex(rp->hash192, 16, str, sizeof(str));
3131 print("Hash C from P-192: %s", str);
3133 bin2hex(rp->rand192, 16, str, sizeof(str));
3134 print("Randomizer R with P-192: %s", str);
3136 if (len < sizeof(*rp))
3137 return noninteractive_quit(EXIT_SUCCESS);
3139 bin2hex(rp->hash256, 16, str, sizeof(str));
3140 print("Hash C from P-256: %s", str);
3142 bin2hex(rp->rand256, 16, str, sizeof(str));
3143 print("Randomizer R with P-256: %s", str);
3145 noninteractive_quit(EXIT_SUCCESS);
3148 static void cmd_local_oob(struct mgmt *mgmt, uint16_t index,
3149 int argc, char **argv)
3151 if (index == MGMT_INDEX_NONE)
3154 if (mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL,
3155 local_oob_rsp, NULL, NULL) == 0) {
3156 error("Unable to send read_local_oob cmd");
3157 return noninteractive_quit(EXIT_FAILURE);
3161 static void remote_oob_rsp(uint8_t status, uint16_t len, const void *param,
3164 const struct mgmt_addr_info *rp = param;
3168 error("Add Remote OOB Data failed: 0x%02x (%s)",
3169 status, mgmt_errstr(status));
3173 if (len < sizeof(*rp)) {
3174 error("Too small (%u bytes) add_remote_oob rsp", len);
3178 ba2str(&rp->bdaddr, addr);
3179 print("Remote OOB data added for %s (%u)", addr, rp->type);
3182 static void remote_oob_usage(void)
3184 print("Usage: remote-oob [-t <addr_type>] "
3185 "[-r <rand192>] [-h <hash192>] [-R <rand256>] [-H <hash256>] "
3189 static struct option remote_oob_opt[] = {
3190 { "help", 0, 0, 'h' },
3191 { "type", 1, 0, 't' },
3195 static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index,
3196 int argc, char **argv)
3198 struct mgmt_cp_add_remote_oob_data cp;
3201 memset(&cp, 0, sizeof(cp));
3202 cp.addr.type = BDADDR_BREDR;
3204 while ((opt = getopt_long(argc, argv, "+t:r:R:h:H:",
3205 remote_oob_opt, NULL)) != -1) {
3208 cp.addr.type = strtol(optarg, NULL, 0);
3211 hex2bin(optarg, cp.rand192, 16);
3214 hex2bin(optarg, cp.hash192, 16);
3217 hex2bin(optarg, cp.rand256, 16);
3220 hex2bin(optarg, cp.hash256, 16);
3224 return noninteractive_quit(EXIT_FAILURE);
3234 return noninteractive_quit(EXIT_FAILURE);
3237 if (index == MGMT_INDEX_NONE)
3240 str2ba(argv[0], &cp.addr.bdaddr);
3242 print("Adding OOB data for %s (%s)", argv[0], typestr(cp.addr.type));
3244 if (mgmt_send(mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA, index,
3245 sizeof(cp), &cp, remote_oob_rsp,
3247 error("Unable to send add_remote_oob cmd");
3248 return noninteractive_quit(EXIT_FAILURE);
3252 static void did_rsp(uint8_t status, uint16_t len, const void *param,
3256 error("Set Device ID failed with status 0x%02x (%s)",
3257 status, mgmt_errstr(status));
3259 print("Device ID successfully set");
3261 noninteractive_quit(EXIT_SUCCESS);
3264 static void did_usage(void)
3266 print("Usage: did <source>:<vendor>:<product>:<version>");
3267 print(" possible source values: bluetooth, usb");
3270 static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
3272 struct mgmt_cp_set_device_id cp;
3273 uint16_t vendor, product, version , source;
3278 return noninteractive_quit(EXIT_FAILURE);
3281 result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product,
3288 result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product,
3296 return noninteractive_quit(EXIT_FAILURE);
3299 if (index == MGMT_INDEX_NONE)
3302 cp.source = htobs(source);
3303 cp.vendor = htobs(vendor);
3304 cp.product = htobs(product);
3305 cp.version = htobs(version);
3307 if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_ID, index, sizeof(cp), &cp,
3308 did_rsp, NULL, NULL) == 0) {
3309 error("Unable to send set_device_id cmd");
3310 return noninteractive_quit(EXIT_FAILURE);
3314 static void static_addr_rsp(uint8_t status, uint16_t len, const void *param,
3318 error("Set static address failed with status 0x%02x (%s)",
3319 status, mgmt_errstr(status));
3321 print("Static address successfully set");
3323 noninteractive_quit(EXIT_SUCCESS);
3326 static void static_addr_usage(void)
3328 print("Usage: static-addr <address>");
3331 static void cmd_static_addr(struct mgmt *mgmt, uint16_t index,
3332 int argc, char **argv)
3334 struct mgmt_cp_set_static_address cp;
3337 static_addr_usage();
3338 return noninteractive_quit(EXIT_FAILURE);
3341 if (index == MGMT_INDEX_NONE)
3344 str2ba(argv[1], &cp.bdaddr);
3346 if (mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, sizeof(cp), &cp,
3347 static_addr_rsp, NULL, NULL) == 0) {
3348 error("Unable to send set_static_address cmd");
3349 return noninteractive_quit(EXIT_FAILURE);
3353 static void options_rsp(uint16_t op, uint16_t id, uint8_t status,
3354 uint16_t len, const void *param)
3356 const uint32_t *rp = param;
3359 error("%s for hci%u failed with status 0x%02x (%s)",
3360 mgmt_opstr(op), id, status, mgmt_errstr(status));
3361 return noninteractive_quit(EXIT_FAILURE);
3364 if (len < sizeof(*rp)) {
3365 error("Too small %s response (%u bytes)",
3366 mgmt_opstr(op), len);
3367 return noninteractive_quit(EXIT_FAILURE);
3370 print("hci%u %s complete, options: %s", id, mgmt_opstr(op),
3371 options2str(get_le32(rp)));
3373 noninteractive_quit(EXIT_SUCCESS);
3376 static void cmd_public_addr(struct mgmt *mgmt, uint16_t index,
3377 int argc, char **argv)
3379 struct mgmt_cp_set_public_address cp;
3382 print("Usage: public-addr <address>");
3383 return noninteractive_quit(EXIT_FAILURE);
3386 if (index == MGMT_INDEX_NONE)
3389 str2ba(argv[1], &cp.bdaddr);
3391 if (send_cmd(mgmt, MGMT_OP_SET_PUBLIC_ADDRESS, index, sizeof(cp), &cp,
3392 options_rsp) == 0) {
3393 error("Unable to send Set Public Address cmd");
3394 return noninteractive_quit(EXIT_FAILURE);
3398 static void cmd_ext_config(struct mgmt *mgmt, uint16_t index,
3399 int argc, char **argv)
3401 struct mgmt_cp_set_external_config cp;
3404 print("Specify \"on\" or \"off\"");
3405 return noninteractive_quit(EXIT_FAILURE);
3408 if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
3410 else if (strcasecmp(argv[1], "off") == 0)
3413 cp.config = atoi(argv[1]);
3415 if (index == MGMT_INDEX_NONE)
3418 if (send_cmd(mgmt, MGMT_OP_SET_EXTERNAL_CONFIG, index, sizeof(cp), &cp,
3419 options_rsp) == 0) {
3420 error("Unable to send Set External Config cmd");
3421 return noninteractive_quit(EXIT_FAILURE);
3425 static void cmd_debug_keys(struct mgmt *mgmt, uint16_t index,
3426 int argc, char **argv)
3428 cmd_setting(mgmt, index, MGMT_OP_SET_DEBUG_KEYS, argc, argv);
3431 static void conn_info_rsp(uint8_t status, uint16_t len, const void *param,
3434 const struct mgmt_rp_get_conn_info *rp = param; char addr[18];
3436 if (len == 0 && status != 0) {
3437 error("Get Conn Info failed, status 0x%02x (%s)",
3438 status, mgmt_errstr(status));
3439 return noninteractive_quit(EXIT_FAILURE);
3442 if (len < sizeof(*rp)) {
3443 error("Unexpected Get Conn Info len %u", len);
3444 return noninteractive_quit(EXIT_FAILURE);
3447 ba2str(&rp->addr.bdaddr, addr);
3450 error("Get Conn Info for %s (%s) failed. status 0x%02x (%s)",
3451 addr, typestr(rp->addr.type),
3452 status, mgmt_errstr(status));
3454 print("Connection Information for %s (%s)",
3455 addr, typestr(rp->addr.type));
3456 print("\tRSSI %d\tTX power %d\tmaximum TX power %d",
3457 rp->rssi, rp->tx_power, rp->max_tx_power);
3460 noninteractive_quit(EXIT_SUCCESS);
3463 static void conn_info_usage(void)
3465 print("Usage: conn-info [-t type] <remote address>");
3468 static struct option conn_info_options[] = {
3469 { "help", 0, 0, 'h' },
3470 { "type", 1, 0, 't' },
3474 static void cmd_conn_info(struct mgmt *mgmt, uint16_t index,
3475 int argc, char **argv)
3477 struct mgmt_cp_get_conn_info cp;
3478 uint8_t type = BDADDR_BREDR;
3481 while ((opt = getopt_long(argc, argv, "+t:h", conn_info_options,
3485 type = strtol(optarg, NULL, 0);
3489 return noninteractive_quit(EXIT_SUCCESS);
3492 return noninteractive_quit(EXIT_FAILURE);
3502 return noninteractive_quit(EXIT_FAILURE);
3505 if (index == MGMT_INDEX_NONE)
3508 memset(&cp, 0, sizeof(cp));
3509 str2ba(argv[0], &cp.addr.bdaddr);
3510 cp.addr.type = type;
3512 if (mgmt_send(mgmt, MGMT_OP_GET_CONN_INFO, index, sizeof(cp), &cp,
3513 conn_info_rsp, NULL, NULL) == 0) {
3514 error("Unable to send get_conn_info cmd");
3515 return noninteractive_quit(EXIT_FAILURE);
3519 static void io_cap_rsp(uint8_t status, uint16_t len, const void *param,
3523 error("Could not set IO Capability with status 0x%02x (%s)",
3524 status, mgmt_errstr(status));
3526 print("IO Capabilities successfully set");
3528 noninteractive_quit(EXIT_SUCCESS);
3531 static void io_cap_usage(void)
3533 print("Usage: io-cap <cap>");
3536 static void cmd_io_cap(struct mgmt *mgmt, uint16_t index,
3537 int argc, char **argv)
3539 struct mgmt_cp_set_io_capability cp;
3544 return noninteractive_quit(EXIT_FAILURE);
3547 if (index == MGMT_INDEX_NONE)
3550 cap = strtol(argv[1], NULL, 0);
3551 memset(&cp, 0, sizeof(cp));
3552 cp.io_capability = cap;
3554 if (mgmt_send(mgmt, MGMT_OP_SET_IO_CAPABILITY, index, sizeof(cp), &cp,
3555 io_cap_rsp, NULL, NULL) == 0) {
3556 error("Unable to send set-io-cap cmd");
3557 return noninteractive_quit(EXIT_FAILURE);
3561 static void scan_params_rsp(uint8_t status, uint16_t len, const void *param,
3565 error("Set scan parameters failed with status 0x%02x (%s)",
3566 status, mgmt_errstr(status));
3568 print("Scan parameters successfully set");
3570 noninteractive_quit(EXIT_SUCCESS);
3573 static void scan_params_usage(void)
3575 print("Usage: scan-params <interval> <window>");
3578 static void cmd_scan_params(struct mgmt *mgmt, uint16_t index,
3579 int argc, char **argv)
3581 struct mgmt_cp_set_scan_params cp;
3584 scan_params_usage();
3585 return noninteractive_quit(EXIT_FAILURE);
3588 if (index == MGMT_INDEX_NONE)
3591 cp.interval = strtol(argv[1], NULL, 0);
3592 cp.window = strtol(argv[2], NULL, 0);
3594 if (mgmt_send(mgmt, MGMT_OP_SET_SCAN_PARAMS, index, sizeof(cp), &cp,
3595 scan_params_rsp, NULL, NULL) == 0) {
3596 error("Unable to send set_scan_params cmd");
3597 return noninteractive_quit(EXIT_FAILURE);
3601 static void clock_info_rsp(uint8_t status, uint16_t len, const void *param,
3604 const struct mgmt_rp_get_clock_info *rp = param;
3606 if (len < sizeof(*rp)) {
3607 error("Unexpected Get Clock Info len %u", len);
3608 return noninteractive_quit(EXIT_FAILURE);
3612 error("Get Clock Info failed with status 0x%02x (%s)",
3613 status, mgmt_errstr(status));
3614 return noninteractive_quit(EXIT_FAILURE);
3617 print("Local Clock: %u", le32_to_cpu(rp->local_clock));
3618 print("Piconet Clock: %u", le32_to_cpu(rp->piconet_clock));
3619 print("Accurary: %u", le16_to_cpu(rp->accuracy));
3621 noninteractive_quit(EXIT_SUCCESS);
3624 static void cmd_clock_info(struct mgmt *mgmt, uint16_t index,
3625 int argc, char **argv)
3627 struct mgmt_cp_get_clock_info cp;
3629 if (index == MGMT_INDEX_NONE)
3632 memset(&cp, 0, sizeof(cp));
3635 str2ba(argv[1], &cp.addr.bdaddr);
3637 if (mgmt_send(mgmt, MGMT_OP_GET_CLOCK_INFO, index, sizeof(cp), &cp,
3638 clock_info_rsp, NULL, NULL) == 0) {
3639 error("Unable to send get_clock_info cmd");
3640 return noninteractive_quit(EXIT_FAILURE);
3644 static void add_device_rsp(uint8_t status, uint16_t len, const void *param,
3648 error("Add device failed with status 0x%02x (%s)",
3649 status, mgmt_errstr(status));
3650 noninteractive_quit(EXIT_SUCCESS);
3653 static void add_device_usage(void)
3655 print("Usage: add-device [-a action] [-t type] <address>");
3658 static struct option add_device_options[] = {
3659 { "help", 0, 0, 'h' },
3660 { "action", 1, 0, 'a' },
3661 { "type", 1, 0, 't' },
3665 static void cmd_add_device(struct mgmt *mgmt, uint16_t index,
3666 int argc, char **argv)
3668 struct mgmt_cp_add_device cp;
3669 uint8_t action = 0x00;
3670 uint8_t type = BDADDR_BREDR;
3674 while ((opt = getopt_long(argc, argv, "+a:t:h", add_device_options,
3678 action = strtol(optarg, NULL, 0);
3681 type = strtol(optarg, NULL, 0);
3685 return noninteractive_quit(EXIT_SUCCESS);
3688 return noninteractive_quit(EXIT_FAILURE);
3698 return noninteractive_quit(EXIT_FAILURE);
3701 if (index == MGMT_INDEX_NONE)
3704 memset(&cp, 0, sizeof(cp));
3705 str2ba(argv[0], &cp.addr.bdaddr);
3706 cp.addr.type = type;
3709 ba2str(&cp.addr.bdaddr, addr);
3710 print("Adding device with %s (%s)", addr, typestr(cp.addr.type));
3712 if (mgmt_send(mgmt, MGMT_OP_ADD_DEVICE, index, sizeof(cp), &cp,
3713 add_device_rsp, NULL, NULL) == 0) {
3714 error("Unable to send add device command");
3715 return noninteractive_quit(EXIT_FAILURE);
3719 static void remove_device_rsp(uint8_t status, uint16_t len, const void *param,
3723 error("Remove device failed with status 0x%02x (%s)",
3724 status, mgmt_errstr(status));
3725 noninteractive_quit(EXIT_SUCCESS);
3728 static void del_device_usage(void)
3730 print("Usage: del-device [-t type] <address>");
3733 static struct option del_device_options[] = {
3734 { "help", 0, 0, 'h' },
3735 { "type", 1, 0, 't' },
3739 static void cmd_del_device(struct mgmt *mgmt, uint16_t index,
3740 int argc, char **argv)
3742 struct mgmt_cp_remove_device cp;
3743 uint8_t type = BDADDR_BREDR;
3747 while ((opt = getopt_long(argc, argv, "+t:h", del_device_options,
3751 type = strtol(optarg, NULL, 0);
3755 return noninteractive_quit(EXIT_SUCCESS);
3758 return noninteractive_quit(EXIT_FAILURE);
3768 return noninteractive_quit(EXIT_FAILURE);
3771 if (index == MGMT_INDEX_NONE)
3774 memset(&cp, 0, sizeof(cp));
3775 str2ba(argv[0], &cp.addr.bdaddr);
3776 cp.addr.type = type;
3778 ba2str(&cp.addr.bdaddr, addr);
3779 print("Removing device with %s (%s)", addr, typestr(cp.addr.type));
3781 if (mgmt_send(mgmt, MGMT_OP_REMOVE_DEVICE, index, sizeof(cp), &cp,
3782 remove_device_rsp, NULL, NULL) == 0) {
3783 error("Unable to send remove device command");
3784 return noninteractive_quit(EXIT_FAILURE);
3788 static void cmd_clr_devices(struct mgmt *mgmt, uint16_t index,
3789 int argc, char **argv)
3791 char *bdaddr_any = "00:00:00:00:00:00";
3792 char *rm_argv[] = { "del-device", bdaddr_any, NULL };
3794 cmd_del_device(mgmt, index, 2, rm_argv);
3797 static void local_oob_ext_rsp(uint8_t status, uint16_t len, const void *param,
3800 const struct mgmt_rp_read_local_oob_ext_data *rp = param;
3804 error("Read Local OOB Ext Data failed with status 0x%02x (%s)",
3805 status, mgmt_errstr(status));
3806 return noninteractive_quit(EXIT_FAILURE);
3809 if (len < sizeof(*rp)) {
3810 error("Too small (%u bytes) read_local_oob_ext rsp", len);
3811 return noninteractive_quit(EXIT_FAILURE);
3814 eir_len = le16_to_cpu(rp->eir_len);
3815 if (len != sizeof(*rp) + eir_len) {
3816 error("local_oob_ext: expected %zu bytes, got %u bytes",
3817 sizeof(*rp) + eir_len, len);
3818 return noninteractive_quit(EXIT_FAILURE);
3821 print_eir(rp->eir, eir_len);
3823 noninteractive_quit(EXIT_SUCCESS);
3826 static void cmd_bredr_oob(struct mgmt *mgmt, uint16_t index,
3827 int argc, char **argv)
3829 struct mgmt_cp_read_local_oob_ext_data cp;
3831 if (index == MGMT_INDEX_NONE)
3834 cp.type = SCAN_TYPE_BREDR;
3836 if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
3837 index, sizeof(cp), &cp,
3838 local_oob_ext_rsp, NULL, NULL)) {
3839 error("Unable to send read_local_oob_ext cmd");
3840 return noninteractive_quit(EXIT_FAILURE);
3844 static void cmd_le_oob(struct mgmt *mgmt, uint16_t index,
3845 int argc, char **argv)
3847 struct mgmt_cp_read_local_oob_ext_data cp;
3849 if (index == MGMT_INDEX_NONE)
3852 cp.type = SCAN_TYPE_LE;
3854 if (!mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
3855 index, sizeof(cp), &cp,
3856 local_oob_ext_rsp, NULL, NULL)) {
3857 error("Unable to send read_local_oob_ext cmd");
3858 return noninteractive_quit(EXIT_FAILURE);
3862 static const char *adv_flags_str[] = {
3864 "general-discoverable",
3865 "limited-discoverable",
3868 "scan-rsp-appearance",
3869 "scan-rsp-local-name",
3872 static const char *adv_flags2str(uint32_t flags)
3874 static char str[256];
3881 for (i = 0; i < NELEM(adv_flags_str); i++) {
3882 if ((flags & (1 << i)) != 0)
3883 off += snprintf(str + off, sizeof(str) - off, "%s ",
3890 static void adv_features_rsp(uint8_t status, uint16_t len, const void *param,
3893 const struct mgmt_rp_read_adv_features *rp = param;
3894 uint32_t supported_flags;
3897 error("Reading adv features failed with status 0x%02x (%s)",
3898 status, mgmt_errstr(status));
3899 return noninteractive_quit(EXIT_FAILURE);
3902 if (len < sizeof(*rp)) {
3903 error("Too small adv features reply (%u bytes)", len);
3904 return noninteractive_quit(EXIT_FAILURE);
3907 if (len < sizeof(*rp) + rp->num_instances * sizeof(uint8_t)) {
3908 error("Instances count (%u) doesn't match reply length (%u)",
3909 rp->num_instances, len);
3910 return noninteractive_quit(EXIT_FAILURE);
3913 supported_flags = le32_to_cpu(rp->supported_flags);
3914 print("Supported flags: %s", adv_flags2str(supported_flags));
3915 print("Max advertising data len: %u", rp->max_adv_data_len);
3916 print("Max scan response data len: %u", rp->max_scan_rsp_len);
3917 print("Max instances: %u", rp->max_instances);
3919 print("Instances list with %u item%s", rp->num_instances,
3920 rp->num_instances != 1 ? "s" : "");
3922 return noninteractive_quit(EXIT_SUCCESS);
3925 static void cmd_advinfo(struct mgmt *mgmt, uint16_t index,
3926 int argc, char **argv)
3928 if (index == MGMT_INDEX_NONE)
3931 if (!mgmt_send(mgmt, MGMT_OP_READ_ADV_FEATURES, index, 0, NULL,
3932 adv_features_rsp, NULL, NULL)) {
3933 error("Unable to send advertising features command");
3934 return noninteractive_quit(EXIT_FAILURE);
3938 static void adv_size_info_rsp(uint8_t status, uint16_t len, const void *param,
3941 const struct mgmt_rp_get_adv_size_info *rp = param;
3945 error("Reading adv size info failed with status 0x%02x (%s)",
3946 status, mgmt_errstr(status));
3947 return noninteractive_quit(EXIT_FAILURE);
3950 if (len < sizeof(*rp)) {
3951 error("Too small adv size info reply (%u bytes)", len);
3952 return noninteractive_quit(EXIT_FAILURE);
3955 flags = le32_to_cpu(rp->flags);
3956 print("Instance: %u", rp->instance);
3957 print("Flags: %s", adv_flags2str(flags));
3958 print("Max advertising data len: %u", rp->max_adv_data_len);
3959 print("Max scan response data len: %u", rp->max_scan_rsp_len);
3961 return noninteractive_quit(EXIT_SUCCESS);
3964 static void advsize_usage(void)
3966 print("Usage: advsize [options] <instance_id>\nOptions:\n"
3967 "\t -c, --connectable \"connectable\" flag\n"
3968 "\t -g, --general-discov \"general-discoverable\" flag\n"
3969 "\t -l, --limited-discov \"limited-discoverable\" flag\n"
3970 "\t -m, --managed-flags \"managed-flags\" flag\n"
3971 "\t -p, --tx-power \"tx-power\" flag\n"\
3972 "\t -a, --appearance \"appearance\" flag\n"\
3973 "\t -n, --local-name \"local-name\" flag");
3976 static struct option advsize_options[] = {
3977 { "help", 0, 0, 'h' },
3978 { "connectable", 0, 0, 'c' },
3979 { "general-discov", 0, 0, 'g' },
3980 { "limited-discov", 0, 0, 'l' },
3981 { "managed-flags", 0, 0, 'm' },
3982 { "tx-power", 0, 0, 'p' },
3983 { "appearance", 0, 0, 'a' },
3984 { "local-name", 0, 0, 'n' },
3988 static void cmd_advsize(struct mgmt *mgmt, uint16_t index,
3989 int argc, char **argv)
3991 struct mgmt_cp_get_adv_size_info cp;
3996 while ((opt = getopt_long(argc, argv, "+cglmphna",
3997 advsize_options, NULL)) != -1) {
4000 flags |= MGMT_ADV_FLAG_CONNECTABLE;
4003 flags |= MGMT_ADV_FLAG_DISCOV;
4006 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
4009 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
4012 flags |= MGMT_ADV_FLAG_TX_POWER;
4015 flags |= MGMT_ADV_FLAG_APPEARANCE;
4018 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
4022 return noninteractive_quit(EXIT_FAILURE);
4032 return noninteractive_quit(EXIT_FAILURE);
4035 instance = strtol(argv[0], NULL, 0);
4037 if (index == MGMT_INDEX_NONE)
4040 memset(&cp, 0, sizeof(cp));
4042 cp.instance = instance;
4043 cp.flags = cpu_to_le32(flags);
4045 if (!mgmt_send(mgmt, MGMT_OP_GET_ADV_SIZE_INFO, index, sizeof(cp), &cp,
4046 adv_size_info_rsp, NULL, NULL)) {
4047 error("Unable to send advertising size info command");
4048 return noninteractive_quit(EXIT_FAILURE);
4052 static void add_adv_rsp(uint8_t status, uint16_t len, const void *param,
4055 const struct mgmt_rp_add_advertising *rp = param;
4058 error("Add Advertising failed with status 0x%02x (%s)",
4059 status, mgmt_errstr(status));
4060 return noninteractive_quit(EXIT_FAILURE);
4063 if (len != sizeof(*rp)) {
4064 error("Invalid Add Advertising response length (%u)", len);
4065 return noninteractive_quit(EXIT_FAILURE);
4068 print("Instance added: %u", rp->instance);
4070 return noninteractive_quit(EXIT_SUCCESS);
4073 static void add_adv_usage(void)
4075 print("Usage: add-adv [options] <instance_id>\nOptions:\n"
4076 "\t -u, --uuid <uuid> Service UUID\n"
4077 "\t -d, --adv-data <data> Advertising Data bytes\n"
4078 "\t -s, --scan-rsp <data> Scan Response Data bytes\n"
4079 "\t -t, --timeout <timeout> Timeout in seconds\n"
4080 "\t -D, --duration <duration> Duration in seconds\n"
4081 "\t -c, --connectable \"connectable\" flag\n"
4082 "\t -g, --general-discov \"general-discoverable\" flag\n"
4083 "\t -l, --limited-discov \"limited-discoverable\" flag\n"
4084 "\t -n, --scan-rsp-local-name \"local-name\" flag\n"
4085 "\t -a, --scan-rsp-appearance \"appearance\" flag\n"
4086 "\t -m, --managed-flags \"managed-flags\" flag\n"
4087 "\t -p, --tx-power \"tx-power\" flag\n"
4089 "\tadd-adv -u 180d -u 180f -d 080954657374204C45 1");
4092 static struct option add_adv_options[] = {
4093 { "help", 0, 0, 'h' },
4094 { "uuid", 1, 0, 'u' },
4095 { "adv-data", 1, 0, 'd' },
4096 { "scan-rsp", 1, 0, 's' },
4097 { "timeout", 1, 0, 't' },
4098 { "duration", 1, 0, 'D' },
4099 { "connectable", 0, 0, 'c' },
4100 { "general-discov", 0, 0, 'g' },
4101 { "limited-discov", 0, 0, 'l' },
4102 { "managed-flags", 0, 0, 'm' },
4103 { "tx-power", 0, 0, 'p' },
4107 static bool parse_bytes(char *optarg, uint8_t **bytes, size_t *len)
4116 *len = strlen(optarg);
4119 error("Malformed data");
4124 if (*len > UINT8_MAX) {
4125 error("Data too long");
4129 *bytes = malloc(*len);
4131 error("Failed to allocate memory");
4135 for (i = 0; i < *len; i++) {
4136 if (sscanf(optarg + (i * 2), "%2hhx", *bytes + i) != 1) {
4137 error("Invalid data");
4147 #define MAX_AD_UUID_BYTES 32
4149 static void cmd_add_adv(struct mgmt *mgmt, uint16_t index,
4150 int argc, char **argv)
4152 struct mgmt_cp_add_advertising *cp = NULL;
4154 uint8_t *adv_data = NULL, *scan_rsp = NULL;
4155 size_t adv_len = 0, scan_rsp_len = 0;
4157 uint8_t uuids[MAX_AD_UUID_BYTES];
4158 size_t uuid_bytes = 0;
4159 uint8_t uuid_type = 0;
4160 uint16_t timeout = 0, duration = 0;
4163 bool success = false;
4167 while ((opt = getopt_long(argc, argv, "+u:d:s:t:D:cglmphna",
4168 add_adv_options, NULL)) != -1) {
4171 if (bt_string2uuid(&uuid, optarg) < 0) {
4172 print("Invalid UUID: %s", optarg);
4176 if (uuid_type && uuid_type != uuid.type) {
4177 print("UUID types must be consistent");
4181 if (uuid.type == SDP_UUID16) {
4182 if (uuid_bytes + 2 >= MAX_AD_UUID_BYTES) {
4183 print("Too many UUIDs");
4187 put_le16(uuid.value.uuid16, uuids + uuid_bytes);
4189 } else if (uuid.type == SDP_UUID128) {
4190 if (uuid_bytes + 16 >= MAX_AD_UUID_BYTES) {
4191 print("Too many UUIDs");
4195 bswap_128(uuid.value.uuid128.data,
4196 uuids + uuid_bytes);
4199 printf("Unsupported UUID type");
4204 uuid_type = uuid.type;
4209 print("Only one adv-data option allowed");
4213 if (!parse_bytes(optarg, &adv_data, &adv_len))
4218 print("Only one scan-rsp option allowed");
4222 if (!parse_bytes(optarg, &scan_rsp, &scan_rsp_len))
4226 timeout = strtol(optarg, NULL, 0);
4229 duration = strtol(optarg, NULL, 0);
4232 flags |= MGMT_ADV_FLAG_CONNECTABLE;
4235 flags |= MGMT_ADV_FLAG_DISCOV;
4238 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
4241 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
4244 flags |= MGMT_ADV_FLAG_TX_POWER;
4247 flags |= MGMT_ADV_FLAG_LOCAL_NAME;
4250 flags |= MGMT_ADV_FLAG_APPEARANCE;
4272 instance = strtol(argv[0], NULL, 0);
4274 if (index == MGMT_INDEX_NONE)
4277 cp_len = sizeof(*cp) + uuid_bytes + adv_len + scan_rsp_len;
4278 cp = malloc0(cp_len);
4282 cp->instance = instance;
4283 put_le32(flags, &cp->flags);
4284 put_le16(timeout, &cp->timeout);
4285 put_le16(duration, &cp->duration);
4286 cp->adv_data_len = adv_len + uuid_bytes;
4287 cp->scan_rsp_len = scan_rsp_len;
4290 cp->data[0] = uuid_bytes - 1;
4291 cp->data[1] = uuid_type == SDP_UUID16 ? 0x03 : 0x07;
4292 memcpy(cp->data + 2, uuids, uuid_bytes - 2);
4295 memcpy(cp->data + uuid_bytes, adv_data, adv_len);
4296 memcpy(cp->data + uuid_bytes + adv_len, scan_rsp, scan_rsp_len);
4298 if (!mgmt_send(mgmt, MGMT_OP_ADD_ADVERTISING, index, cp_len, cp,
4299 add_adv_rsp, NULL, NULL)) {
4300 error("Unable to send \"Add Advertising\" command");
4312 noninteractive_quit(success ? EXIT_SUCCESS : EXIT_FAILURE);
4315 static void rm_adv_rsp(uint8_t status, uint16_t len, const void *param,
4318 const struct mgmt_rp_remove_advertising *rp = param;
4321 error("Remove Advertising failed with status 0x%02x (%s)",
4322 status, mgmt_errstr(status));
4323 return noninteractive_quit(EXIT_FAILURE);
4326 if (len != sizeof(*rp)) {
4327 error("Invalid Remove Advertising response length (%u)", len);
4328 return noninteractive_quit(EXIT_FAILURE);
4331 print("Instance removed: %u", rp->instance);
4333 return noninteractive_quit(EXIT_SUCCESS);
4336 static void rm_adv_usage(void)
4338 print("Usage: rm-adv <instance_id>");
4341 static void cmd_rm_adv(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
4343 struct mgmt_cp_remove_advertising cp;
4348 return noninteractive_quit(EXIT_FAILURE);
4351 instance = strtol(argv[1], NULL, 0);
4353 if (index == MGMT_INDEX_NONE)
4356 memset(&cp, 0, sizeof(cp));
4358 cp.instance = instance;
4360 if (!mgmt_send(mgmt, MGMT_OP_REMOVE_ADVERTISING, index, sizeof(cp), &cp,
4361 rm_adv_rsp, NULL, NULL)) {
4362 error("Unable to send \"Remove Advertising\" command");
4363 return noninteractive_quit(EXIT_FAILURE);
4367 static void cmd_clr_adv(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
4369 char *all_instances = "0";
4370 char *rm_argv[] = { "rm-adv", all_instances, NULL };
4372 cmd_rm_adv(mgmt, index, 2, rm_argv);
4375 static void appearance_rsp(uint8_t status, uint16_t len, const void *param,
4379 error("Could not set Appearance with status 0x%02x (%s)",
4380 status, mgmt_errstr(status));
4382 print("Appearance successfully set");
4384 noninteractive_quit(EXIT_SUCCESS);
4387 static void cmd_appearance(struct mgmt *mgmt, uint16_t index, int argc,
4390 struct mgmt_cp_set_appearance cp;
4393 print("Usage: appearance <appearance>");
4394 return noninteractive_quit(EXIT_FAILURE);
4397 if (index == MGMT_INDEX_NONE)
4400 cp.appearance = cpu_to_le16(strtol(argv[1], NULL, 0));
4402 if (mgmt_send(mgmt, MGMT_OP_SET_APPEARANCE, index, sizeof(cp), &cp,
4403 appearance_rsp, NULL, NULL) == 0) {
4404 error("Unable to send appearance cmd");
4405 return noninteractive_quit(EXIT_FAILURE);
4411 void (*func)(struct mgmt *mgmt, uint16_t index, int argc, char **argv);
4413 char * (*gen) (const char *text, int state);
4414 void (*disp) (char **matches, int num_matches, int max_length);
4417 static struct cmd_info all_cmd[] = {
4418 { "version", cmd_version, "Get the MGMT Version" },
4419 { "commands", cmd_commands, "List supported commands" },
4420 { "config", cmd_config, "Show configuration info" },
4421 { "info", cmd_info, "Show controller info" },
4422 { "extinfo", cmd_extinfo, "Show extended controller info" },
4423 { "auto-power", cmd_auto_power, "Power all available features" },
4424 { "power", cmd_power, "Toggle powered state" },
4425 { "discov", cmd_discov, "Toggle discoverable state" },
4426 { "connectable",cmd_connectable,"Toggle connectable state" },
4427 { "fast-conn", cmd_fast_conn, "Toggle fast connectable state" },
4428 { "bondable", cmd_bondable, "Toggle bondable state" },
4429 { "pairable", cmd_bondable, "Toggle bondable state" },
4430 { "linksec", cmd_linksec, "Toggle link level security" },
4431 { "ssp", cmd_ssp, "Toggle SSP mode" },
4432 { "sc", cmd_sc, "Toogle SC support" },
4433 { "hs", cmd_hs, "Toggle HS support" },
4434 { "le", cmd_le, "Toggle LE support" },
4435 { "advertising",cmd_advertising,"Toggle LE advertising", },
4436 { "bredr", cmd_bredr, "Toggle BR/EDR support", },
4437 { "privacy", cmd_privacy, "Toggle privacy support" },
4438 { "class", cmd_class, "Set device major/minor class" },
4439 { "disconnect", cmd_disconnect, "Disconnect device" },
4440 { "con", cmd_con, "List connections" },
4441 { "find", cmd_find, "Discover nearby devices" },
4442 { "find-service", cmd_find_service, "Discover nearby service" },
4443 { "stop-find", cmd_stop_find, "Stop discovery" },
4444 { "name", cmd_name, "Set local name" },
4445 { "pair", cmd_pair, "Pair with a remote device" },
4446 { "cancelpair", cmd_cancel_pair,"Cancel pairing" },
4447 { "unpair", cmd_unpair, "Unpair device" },
4448 { "keys", cmd_keys, "Load Link Keys" },
4449 { "ltks", cmd_ltks, "Load Long Term Keys" },
4450 { "irks", cmd_irks, "Load Identity Resolving Keys" },
4451 { "block", cmd_block, "Block Device" },
4452 { "unblock", cmd_unblock, "Unblock Device" },
4453 { "add-uuid", cmd_add_uuid, "Add UUID" },
4454 { "rm-uuid", cmd_remove_uuid,"Remove UUID" },
4455 { "clr-uuids", cmd_clr_uuids, "Clear UUIDs" },
4456 { "local-oob", cmd_local_oob, "Local OOB data" },
4457 { "remote-oob", cmd_remote_oob, "Remote OOB data" },
4458 { "did", cmd_did, "Set Device ID" },
4459 { "static-addr",cmd_static_addr,"Set static address" },
4460 { "public-addr",cmd_public_addr,"Set public address" },
4461 { "ext-config", cmd_ext_config, "External configuration" },
4462 { "debug-keys", cmd_debug_keys, "Toogle debug keys" },
4463 { "conn-info", cmd_conn_info, "Get connection information" },
4464 { "io-cap", cmd_io_cap, "Set IO Capability" },
4465 { "scan-params",cmd_scan_params,"Set Scan Parameters" },
4466 { "get-clock", cmd_clock_info, "Get Clock Information" },
4467 { "add-device", cmd_add_device, "Add Device" },
4468 { "del-device", cmd_del_device, "Remove Device" },
4469 { "clr-devices",cmd_clr_devices,"Clear Devices" },
4470 { "bredr-oob", cmd_bredr_oob, "Local OOB data (BR/EDR)" },
4471 { "le-oob", cmd_le_oob, "Local OOB data (LE)" },
4472 { "advinfo", cmd_advinfo, "Show advertising features" },
4473 { "advsize", cmd_advsize, "Show advertising size info" },
4474 { "add-adv", cmd_add_adv, "Add advertising instance" },
4475 { "rm-adv", cmd_rm_adv, "Remove advertising instance" },
4476 { "clr-adv", cmd_clr_adv, "Clear advertising instances" },
4477 { "appearance", cmd_appearance, "Set appearance" },
4480 static void cmd_quit(struct mgmt *mgmt, uint16_t index,
4481 int argc, char **argv)
4483 mainloop_exit_success();
4486 static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index)
4488 mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error,
4490 mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added,
4492 mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed,
4494 mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings,
4496 mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering,
4498 mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key,
4500 mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected,
4502 mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected,
4504 mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed,
4506 mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed,
4508 mgmt_register(mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED, index,
4509 class_of_dev_changed, NULL, NULL);
4510 mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index,
4511 local_name_changed, NULL, NULL);
4512 mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found,
4514 mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin,
4516 mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm,
4518 mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index,
4519 request_passkey, mgmt, NULL);
4520 mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index,
4521 passkey_notify, mgmt, NULL);
4522 mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index,
4523 unconf_index_added, NULL, NULL);
4524 mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index,
4525 unconf_index_removed, NULL, NULL);
4526 mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index,
4527 new_config_options, NULL, NULL);
4528 mgmt_register(mgmt, MGMT_EV_EXT_INDEX_ADDED, index,
4529 ext_index_added, NULL, NULL);
4530 mgmt_register(mgmt, MGMT_EV_EXT_INDEX_REMOVED, index,
4531 ext_index_removed, NULL, NULL);
4532 mgmt_register(mgmt, MGMT_EV_LOCAL_OOB_DATA_UPDATED, index,
4533 local_oob_data_updated, NULL, NULL);
4534 mgmt_register(mgmt, MGMT_EV_ADVERTISING_ADDED, index,
4535 advertising_added, NULL, NULL);
4536 mgmt_register(mgmt, MGMT_EV_ADVERTISING_REMOVED, index,
4537 advertising_removed, NULL, NULL);
4540 static void cmd_select(struct mgmt *mgmt, uint16_t index,
4541 int argc, char **argv)
4544 error("Usage: select <index>");
4548 mgmt_cancel_all(mgmt);
4549 mgmt_unregister_all(mgmt);
4551 if (!strcmp(argv[1], "none") || !strcmp(argv[1], "any") ||
4552 !strcmp(argv[1], "all"))
4553 mgmt_index = MGMT_INDEX_NONE;
4554 else if (!strncmp(argv[1], "hci", 3))
4555 mgmt_index = atoi(&argv[1][3]);
4557 mgmt_index = atoi(argv[1]);
4559 register_mgmt_callbacks(mgmt, mgmt_index);
4561 print("Selected index %u", mgmt_index);
4563 update_prompt(mgmt_index);
4566 static struct cmd_info interactive_cmd[] = {
4567 { "select", cmd_select, "Select a different index" },
4568 { "quit", cmd_quit, "Exit program" },
4569 { "exit", cmd_quit, "Exit program" },
4570 { "help", NULL, "List supported commands" },
4573 static char *cmd_generator(const char *text, int state)
4575 static size_t i, j, len;
4584 while (i < NELEM(all_cmd)) {
4585 cmd = all_cmd[i++].cmd;
4587 if (!strncmp(cmd, text, len))
4591 while (j < NELEM(interactive_cmd)) {
4592 cmd = interactive_cmd[j++].cmd;
4594 if (!strncmp(cmd, text, len))
4601 static char **cmd_completion(const char *text, int start, int end)
4603 char **matches = NULL;
4608 for (i = 0; i < NELEM(all_cmd); i++) {
4609 struct cmd_info *c = &all_cmd[i];
4611 if (strncmp(c->cmd, rl_line_buffer, start - 1))
4617 rl_completion_display_matches_hook = c->disp;
4618 matches = rl_completion_matches(text, c->gen);
4622 rl_completion_display_matches_hook = NULL;
4623 matches = rl_completion_matches(text, cmd_generator);
4627 rl_attempted_completion_over = 1;
4632 static struct cmd_info *find_cmd(const char *cmd, struct cmd_info table[],
4637 for (i = 0; i < cmd_count; i++) {
4638 if (!strcmp(table[i].cmd, cmd))
4645 static void rl_handler(char *input)
4653 rl_insert_text("quit");
4663 if (prompt_input(input))
4668 if (wordexp(input, &w, WRDE_NOCMD))
4671 if (w.we_wordc == 0)
4674 cmd = w.we_wordv[0];
4678 c = find_cmd(cmd, all_cmd, NELEM(all_cmd));
4679 if (!c && interactive)
4680 c = find_cmd(cmd, interactive_cmd, NELEM(interactive_cmd));
4683 c->func(mgmt, mgmt_index, argc, argv);
4687 if (strcmp(cmd, "help")) {
4688 print("Invalid command");
4692 print("Available commands:");
4694 for (i = 0; i < NELEM(all_cmd); i++) {
4697 print(" %s %-*s %s", c->cmd,
4698 (int)(25 - strlen(c->cmd)), "", c->doc ? : "");
4704 for (i = 0; i < NELEM(interactive_cmd); i++) {
4705 c = &interactive_cmd[i];
4707 print(" %s %-*s %s", c->cmd,
4708 (int)(25 - strlen(c->cmd)), "", c->doc ? : "");
4717 static void usage(void)
4721 printf("btmgmt ver %s\n", VERSION);
4723 "\tbtmgmt [options] <command> [command parameters]\n");
4726 "\t--index <id>\tSpecify adapter index\n"
4727 "\t--verbose\tEnable extra logging\n"
4728 "\t--help\tDisplay help\n");
4730 printf("Commands:\n");
4731 for (i = 0; i < NELEM(all_cmd); i++)
4732 printf("\t%-15s\t%s\n", all_cmd[i].cmd, all_cmd[i].doc);
4735 "For more information on the usage of each command use:\n"
4736 "\tbtmgmt <command> --help\n" );
4739 static struct option main_options[] = {
4740 { "index", 1, 0, 'i' },
4741 { "verbose", 0, 0, 'v' },
4742 { "help", 0, 0, 'h' },
4746 static bool prompt_read(struct io *io, void *user_data)
4748 rl_callback_read_char();
4752 static struct io *setup_stdin(void)
4756 io = io_new(STDIN_FILENO);
4760 io_set_read_handler(io, prompt_read, NULL, NULL);
4765 static void mgmt_debug(const char *str, void *user_data)
4767 const char *prefix = user_data;
4769 print("%s%s", prefix, str);
4772 int main(int argc, char *argv[])
4775 uint16_t index = MGMT_INDEX_NONE;
4778 while ((opt = getopt_long(argc, argv, "+hi:",
4779 main_options, NULL)) != -1) {
4782 if (strlen(optarg) > 3 &&
4783 strncasecmp(optarg, "hci", 3) == 0)
4784 index = atoi(optarg + 3);
4786 index = atoi(optarg);
4801 mgmt = mgmt_new_default();
4803 fprintf(stderr, "Unable to open mgmt_socket\n");
4804 return EXIT_FAILURE;
4807 if (getenv("MGMT_DEBUG"))
4808 mgmt_set_debug(mgmt, mgmt_debug, "mgmt: ", NULL);
4813 c = find_cmd(argv[0], all_cmd, NELEM(all_cmd));
4815 fprintf(stderr, "Unknown command: %s\n", argv[0]);
4817 return EXIT_FAILURE;
4820 c->func(mgmt, index, argc, argv);
4823 register_mgmt_callbacks(mgmt, index);
4825 /* Interactive mode */
4827 input = setup_stdin();
4834 rl_attempted_completion_function = cmd_completion;
4836 rl_erase_empty_line = 1;
4837 rl_callback_handler_install(NULL, rl_handler);
4839 update_prompt(index);
4845 status = mainloop_run();
4851 rl_callback_handler_remove();
4854 mgmt_cancel_all(mgmt);
4855 mgmt_unregister_all(mgmt);