65 printf(__VA_ARGS__); print_prompt();
67 #define COLOR_OFF "\x1B[0m"
68 #define COLOR_RED "\x1B[0;91m"
69 #define COLOR_GREEN "\x1B[0;92m"
70 #define COLOR_YELLOW "\x1B[0;93m"
71 #define COLOR_BLUE "\x1B[0;94m"
72 #define COLOR_MAGENTA "\x1B[0;95m"
73 #define COLOR_BOLDGRAY "\x1B[1;30m"
74 #define COLOR_BOLDWHITE "\x1B[1;36m"
113 return "Invalid Handle";
115 return "Read Not Permitted";
117 return "Write Not Permitted";
119 return "Invalid PDU";
121 return "Authentication Required";
123 return "Request Not Supported";
125 return "Invalid Offset";
127 return "Authorization Required";
129 return "Prepare Write Queue Full";
131 return "Attribute Not Found";
133 return "Attribute Not Long";
135 return "Insuficient Encryption Key Size";
137 return "Invalid Attribute value len";
139 return "Unlikely Error";
141 return "Insufficient Encryption";
143 return "Group type Not Supported";
145 return "Insufficient Resources";
147 return "CCC Improperly Configured";
149 return "Procedure Already in Progress";
151 return "Out of Range";
153 return "Unknown error type";
165 printf(
"Device disconnected: %s\n", strerror(err));
179 const char *prefix = user_data;
192 const char *prefix = user_data;
197 static void ready_cb(
bool success, uint8_t att_ecode,
void *user_data);
218 PRLOG(
"%s - UUID: %s start: 0x%04x end: 0x%04x\n", str, uuid_str,
257 fprintf(stderr,
"Failed to allocate memory for client\n");
263 fprintf(stderr,
"Failed to initialze ATT transport layer\n");
270 fprintf(stderr,
"Failed to set up ATT transport layer\n");
278 fprintf(stderr,
"Failed to set ATT disconnect handler\n");
287 fprintf(stderr,
"Failed to create GATT database\n");
295 fprintf(stderr,
"Failed to create GATT client\n");
346 printf(
"%s\n", uuid_str);
357 struct client *cli = user_data;
358 uint16_t handle, start, end;
372 "0x%04x, - start: 0x%04x, end: 0x%04x,"
373 "uuid: ", handle, start, end);
386 " - handle: 0x%04x, uuid: ",
399 uint16_t
handle, value_handle;
410 " - start: 0x%04x, value: 0x%04x, "
411 "props: 0x%02x, uuid: ",
412 handle, value_handle, properties);
426 struct client *cli = user_data;
436 "end: 0x%04x, type: %s, uuid: ",
437 start, end, primary ?
"primary" :
"secondary");
492 static void ready_cb(
bool success, uint8_t att_ecode,
void *user_data)
494 struct client *cli = user_data;
497 PRLOG(
"GATT discovery procedures failed - error code: 0x%02x\n",
502 PRLOG(
"GATT discovery procedures complete\n");
518 struct client *cli = user_data;
520 printf(
"\nService Changed handled - start: 0x%04x end: 0x%04x\n",
521 start_handle, end_handle);
524 start_handle, end_handle);
533 printf(
"Usage: services [options]\nOptions:\n"
534 "\t -u, --uuid <uuid>\tService UUID\n"
535 "\t -a, --handle <handle>\tService start handle\n"
536 "\t -h, --help\t\tShow help message\n"
538 "\tservices\n\tservices -u 0x180d\n\tservices -a 0x0009\n");
550 static bool parse_args(
char *str,
int expected_argc,
char **argv,
int *argc)
554 for (ap = argv; (*ap = strsep(&str,
" \t")) != NULL;) {
561 if (*argc > expected_argc)
581 printf(
"GATT client not initialized\n");
600 if (!strcmp(argv[0],
"-u") || !strcmp(argv[0],
"--uuid")) {
604 printf(
"Invalid UUID: %s\n", argv[1]);
611 }
else if (!strcmp(argv[0],
"-a") || !strcmp(argv[0],
"--handle")) {
615 handle = strtol(argv[1], &endptr, 0);
616 if (!endptr || *endptr !=
'\0') {
617 printf(
"Invalid start handle: %s\n", argv[1]);
631 printf(
"Usage: read-multiple <handle_1> <handle_2> ...\n");
644 const uint8_t *value, uint16_t length,
650 PRLOG(
"\nRead multiple request failed: 0x%02x\n", att_ecode);
654 printf(
"\nRead multiple value (%u bytes):", length);
656 for (i = 0; i < length; i++)
657 printf(
"%02x ", value[i]);
677 printf(
"GATT client not initialized\n");
681 if (!
parse_args(cmd_str,
sizeof(argv), argv, &argc) || argc < 2) {
686 value = malloc(
sizeof(uint16_t) * argc);
688 printf(
"Failed to construct value\n");
692 for (i = 0; i < argc; i++) {
693 value[i] = strtol(argv[i], &endptr, 0);
694 if (endptr == argv[i] || *endptr !=
'\0' || !value[i]) {
695 printf(
"Invalid value byte: %s\n", argv[i]);
703 printf(
"Failed to initiate read multiple procedure\n");
713 printf(
"Usage: read-value <value_handle>\n");
725 static void read_cb(
bool success, uint8_t att_ecode,
const uint8_t *value,
726 uint16_t length,
void *user_data)
731 PRLOG(
"\nRead request failed: %s (0x%02x)\n",
736 printf(
"\nRead value");
739 PRLOG(
": 0 bytes\n");
743 printf(
" (%u bytes): ", length);
745 for (i = 0; i < length; i++)
746 printf(
"%02x ", value[i]);
765 printf(
"GATT client not initialized\n");
769 if (!
parse_args(cmd_str, 1, argv, &argc) || argc != 1) {
774 handle = strtol(argv[0], &endptr, 0);
775 if (!endptr || *endptr !=
'\0' || !handle) {
776 printf(
"Invalid value handle: %s\n", argv[0]);
782 printf(
"Failed to initiate read value procedure\n");
790 printf(
"Usage: read-long-value <value_handle> <offset>\n");
808 printf(
"GATT client not initialized\n");
812 if (!
parse_args(cmd_str, 2, argv, &argc) || argc != 2) {
817 handle = strtol(argv[0], &endptr, 0);
818 if (!endptr || *endptr !=
'\0' || !handle) {
819 printf(
"Invalid value handle: %s\n", argv[0]);
824 offset = strtol(argv[1], &endptr, 0);
825 if (!endptr || *endptr !=
'\0') {
826 printf(
"Invalid offset: %s\n", argv[1]);
832 printf(
"Failed to initiate read long value procedure\n");
840 printf(
"Usage: write-value [options] <value_handle> <value>\n"
842 "\t-w, --without-response\tWrite without response\n"
843 "\t-s, --signed-write\tSigned write command\n"
845 "\twrite-value 0x0001 00 01 00\n");
849 {
"without-response", 0, 0,
'w' },
850 {
"signed-write", 0, 0,
's' },
861 static void write_cb(
bool success, uint8_t att_ecode,
void *user_data)
864 PRLOG(
"\nWrite successful\n");
866 PRLOG(
"\nWrite failed: %s (0x%02x)\n",
881 char **argv = argvbuf;
886 uint8_t *value = NULL;
887 bool without_response =
false;
888 bool signed_write =
false;
891 printf(
"GATT client not initialized\n");
895 if (!
parse_args(cmd_str, 514, argv + 1, &argc)) {
896 printf(
"Too many arguments\n");
902 argv[0] =
"write-value";
907 without_response =
true;
926 handle = strtol(argv[0], &endptr, 0);
927 if (!endptr || *endptr !=
'\0' || !handle) {
928 printf(
"Invalid handle: %s\n", argv[0]);
935 if (length > UINT16_MAX) {
936 printf(
"Write value too long\n");
940 value = malloc(length);
942 printf(
"Failed to construct write value\n");
946 for (i = 1; i < argc; i++) {
947 if (strlen(argv[i]) != 2) {
948 printf(
"Invalid value byte: %s\n",
953 value[i-1] = strtol(argv[i], &endptr, 0);
954 if (endptr == argv[i] || *endptr !=
'\0'
955 || errno == ERANGE) {
956 printf(
"Invalid value byte: %s\n",
963 if (without_response) {
965 signed_write, value, length)) {
966 printf(
"Failed to initiate write without response "
971 printf(
"Write command sent\n");
978 printf(
"Failed to initiate write procedure\n");
989 printf(
"Usage: write-long-value [options] <value_handle> <offset> "
992 "\t-r, --reliable-write\tReliable write\n"
994 "\twrite-long-value 0x0001 0 00 01 00\n");
998 {
"reliable-write", 0, 0,
'r' },
1014 PRLOG(
"Write successful\n");
1015 }
else if (reliable_error) {
1016 PRLOG(
"Reliable write not verified\n");
1018 PRLOG(
"\nWrite failed: %s (0x%02x)\n",
1033 char **argv = argvbuf;
1037 char *endptr = NULL;
1039 uint8_t *value = NULL;
1040 bool reliable_writes =
false;
1043 printf(
"GATT client not initialized\n");
1047 if (!
parse_args(cmd_str, 514, argv + 1, &argc)) {
1048 printf(
"Too many arguments\n");
1054 argv[0] =
"write-long-value";
1059 reliable_writes =
true;
1075 handle = strtol(argv[0], &endptr, 0);
1076 if (!endptr || *endptr !=
'\0' || !handle) {
1077 printf(
"Invalid handle: %s\n", argv[0]);
1082 offset = strtol(argv[1], &endptr, 0);
1083 if (!endptr || *endptr !=
'\0' || errno == ERANGE) {
1084 printf(
"Invalid offset: %s\n", argv[1]);
1091 if (length > UINT16_MAX) {
1092 printf(
"Write value too long\n");
1096 value = malloc(length);
1098 printf(
"Failed to construct write value\n");
1102 for (i = 2; i < argc; i++) {
1103 if (strlen(argv[i]) != 2) {
1104 printf(
"Invalid value byte: %s\n",
1110 value[i-2] = strtol(argv[i], &endptr, 0);
1111 if (endptr == argv[i] || *endptr !=
'\0'
1112 || errno == ERANGE) {
1113 printf(
"Invalid value byte: %s\n",
1122 offset, value, length,
1125 printf(
"Failed to initiate long write procedure\n");
1135 printf(
"Usage: write-prepare [options] <value_handle> <offset> "
1138 "\t-s, --session-id\tSession id\n"
1140 "\twrite-prepare -s 1 0x0001 00 01 00\n");
1144 {
"session-id", 1, 0,
's' },
1158 char **argv = argvbuf;
1160 unsigned int id = 0;
1163 char *endptr = NULL;
1164 unsigned int length;
1165 uint8_t *value = NULL;
1168 printf(
"GATT client not initialized\n");
1172 if (!
parse_args(cmd_str, 514, argv + 1, &argc)) {
1173 printf(
"Too many arguments\n");
1180 argv[0] =
"write-prepare";
1210 printf(
"Session id != Ongoing session id (%u!=%u)\n",
id,
1215 handle = strtol(argv[0], &endptr, 0);
1216 if (!endptr || *endptr !=
'\0' || !handle) {
1217 printf(
"Invalid handle: %s\n", argv[0]);
1222 offset = strtol(argv[1], &endptr, 0);
1223 if (!endptr || *endptr !=
'\0' || errno == ERANGE) {
1224 printf(
"Invalid offset: %s\n", argv[1]);
1237 if (length > UINT16_MAX) {
1238 printf(
"Write value too long\n");
1242 value = malloc(length);
1244 printf(
"Failed to allocate memory for value\n");
1248 for (i = 2; i < argc; i++) {
1249 if (strlen(argv[i]) != 2) {
1250 printf(
"Invalid value byte: %s\n", argv[i]);
1255 value[i-2] = strtol(argv[i], &endptr, 0);
1256 if (endptr == argv[i] || *endptr !=
'\0' || errno == ERANGE) {
1257 printf(
"Invalid value byte: %s\n", argv[i]);
1271 printf(
"Failed to proceed prepare write\n");
1273 printf(
"Prepare write success.\n"
1274 "Session id: %d to be used on next write\n",
1285 printf(
"Usage: write-execute <session_id> <execute>\n"
1287 "\twrite-execute 1 0\n");
1299 char **argv = argvbuf;
1301 char *endptr = NULL;
1302 unsigned int session_id;
1306 printf(
"GATT client not initialized\n");
1310 if (!
parse_args(cmd_str, 514, argv, &argc)) {
1311 printf(
"Too many arguments\n");
1321 session_id = strtol(argv[0], &endptr, 0);
1322 if (!endptr || *endptr !=
'\0') {
1323 printf(
"Invalid session id: %s\n", argv[0]);
1328 printf(
"Invalid session id: %u != %u\n", session_id,
1333 execute = !!strtol(argv[1], &endptr, 0);
1334 if (!endptr || *endptr !=
'\0') {
1335 printf(
"Invalid execute: %s\n", argv[1]);
1342 printf(
"Failed to proceed write execute\n");
1355 printf(
"Usage: register-notify <chrc value handle>\n");
1366 static void notify_cb(uint16_t value_handle,
const uint8_t *value,
1367 uint16_t length,
void *user_data)
1371 printf(
"\n\tHandle Value Not/Ind: 0x%04x - ", value_handle);
1374 PRLOG(
"(0 bytes)\n");
1378 printf(
"(%u bytes): ", length);
1380 for (i = 0; i < length; i++)
1381 printf(
"%02x ", value[i]);
1395 PRLOG(
"Failed to register notify handler "
1396 "- error code: 0x%02x\n", att_ecode);
1400 PRLOG(
"Registered notify handler!");
1413 uint16_t value_handle;
1415 char *endptr = NULL;
1418 printf(
"GATT client not initialized\n");
1422 if (!
parse_args(cmd_str, 1, argv, &argc) || argc != 1) {
1427 value_handle = strtol(argv[0], &endptr, 0);
1428 if (!endptr || *endptr !=
'\0' || !value_handle) {
1429 printf(
"Invalid value handle: %s\n", argv[0]);
1437 printf(
"Failed to register notify handler\n");
1441 PRLOG(
"Registering notify handler with id: %u\n",
id);
1449 printf(
"Usage: unregister-notify <notify id>\n");
1463 char *endptr = NULL;
1466 printf(
"GATT client not initialized\n");
1470 if (!
parse_args(cmd_str, 1, argv, &argc) || argc != 1) {
1475 id = strtol(argv[0], &endptr, 0);
1476 if (!endptr || *endptr !=
'\0' || !
id) {
1477 printf(
"Invalid notify id: %s\n", argv[0]);
1482 printf(
"Failed to unregister notify handler with id: %u\n",
id);
1486 printf(
"Unregistered notify handler with id: %u\n",
id);
1494 printf(
"Usage: set_security <level>\n"
1497 "\tset-sec-level 2\n");
1509 char **argv = argvbuf;
1511 char *endptr = NULL;
1515 printf(
"GATT client not initialized\n");
1520 printf(
"Too many arguments\n");
1530 level = strtol(argv[0], &endptr, 0);
1531 if (!endptr || *endptr !=
'\0' || level < 1 || level > 3) {
1532 printf(
"Invalid level: %s\n", argv[0]);
1537 printf(
"Could not set sec level\n");
1539 printf(
"Setting security level %d success\n", level);
1553 printf(
"GATT client not initialized\n");
1559 printf(
"Could not set sec level\n");
1561 printf(
"Security level: %u\n", level);
1575 if (strlen(optarg) != 32) {
1576 printf(
"sign-key length is invalid\n");
1580 for (i = 0; i < 16; i++) {
1581 if (sscanf(optarg + (i * 2),
"%2hhx", &key[i]) != 1)
1593 printf(
"Usage: set-sign-key [options]\nOptions:\n"
1594 "\t -c, --sign-key <csrk>\tCSRK\n"
1596 "\tset-sign-key -c D8515948451FEA320DC05A2E88308188\n");
1608 static uint32_t cnt = 0;
1639 if (!strcmp(argv[0],
"-c") || !strcmp(argv[0],
"--sign-key")) {
1660 {
"help",
cmd_help,
"\tDisplay help message" },
1661 {
"services",
cmd_services,
"\tShow discovered services" },
1663 "\tRead a characteristic or descriptor value" },
1665 "\tRead a long characteristic or desctriptor value" },
1668 "\tWrite a characteristic or descriptor value" },
1670 "Write long characteristic or descriptor value" },
1672 "\tWrite prepare characteristic or descriptor value" },
1674 "\tExecute already prepared write" },
1676 "\tSubscribe to not/ind from a characteristic" },
1678 "Unregister a not/ind session"},
1680 "\tSet security level on le connection"},
1682 "\tGet security level on le connection"},
1684 "\tSet signing key for signed write command"},
1699 printf(
"Commands:\n");
1700 for (i = 0;
command[i].cmd; i++)
1716 char *
cmd = NULL, *args;
1717 struct client *cli = user_data;
1720 if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) {
1725 if ((read = getline(&line, &len, stdin)) == -1)
1734 line[read-1] =
'\0';
1737 while ((cmd = strsep(&args,
" \t")))
1744 for (i = 0;
command[i].cmd; i++) {
1745 if (strcmp(
command[i].cmd, cmd) == 0)
1752 fprintf(stderr,
"Unknown command: %s\n", line);
1795 char srcaddr_str[18], dstaddr_str[18];
1797 ba2str(src, srcaddr_str);
1798 ba2str(dst, dstaddr_str);
1800 printf(
"btgatt-client: Opening L2CAP LE connection on ATT "
1801 "channel:\n\t src: %s\n\tdest: %s\n",
1802 srcaddr_str, dstaddr_str);
1807 perror(
"Failed to create L2CAP socket");
1812 memset(&srcaddr, 0,
sizeof(srcaddr));
1818 if (bind(sock, (
struct sockaddr *)&srcaddr,
sizeof(srcaddr)) < 0) {
1819 perror(
"Failed to bind L2CAP socket");
1825 memset(&btsec, 0,
sizeof(btsec));
1828 sizeof(btsec)) != 0) {
1829 fprintf(stderr,
"Failed to set L2CAP security level\n");
1835 memset(&dstaddr, 0,
sizeof(dstaddr));
1841 printf(
"Connecting to device...");
1844 if (connect(sock, (
struct sockaddr *) &dstaddr,
sizeof(dstaddr)) < 0) {
1845 perror(
" Failed to connect");
1860 printf(
"btgatt-client\n");
1861 printf(
"Usage:\n\tbtgatt-client [options]\n");
1864 "\t-i, --index <id>\t\tSpecify adapter index, e.g. hci0\n"
1865 "\t-d, --dest <addr>\t\tSpecify the destination address\n"
1866 "\t-t, --type [random|public] \tSpecify the LE address type\n"
1867 "\t-m, --mtu <mtu> \t\tThe ATT MTU to use\n"
1868 "\t-s, --security-level <sec> \tSet security level (low|"
1870 "\t-v, --verbose\t\t\tEnable extra logging\n"
1871 "\t-h, --help\t\t\tDisplay help\n");
1874 "btgattclient -v -d C4:BE:84:70:29:04\n");
1878 {
"index", 1, 0,
'i' },
1879 {
"dest", 1, 0,
'd' },
1880 {
"type", 1, 0,
't' },
1881 {
"mtu", 1, 0,
'm' },
1882 {
"security-level", 1, 0,
's' },
1883 {
"verbose", 0, 0,
'v' },
1884 {
"help", 0, 0,
'h' },
1902 bool dst_addr_given =
false;
1903 bdaddr_t src_addr, dst_addr;
1909 while ((opt = getopt_long(argc, argv,
"+hvs:m:t:d:i:",
1914 return EXIT_SUCCESS;
1919 if (strcmp(optarg,
"low") == 0)
1921 else if (strcmp(optarg,
"medium") == 0)
1923 else if (strcmp(optarg,
"high") == 0)
1926 fprintf(stderr,
"Invalid security level\n");
1927 return EXIT_FAILURE;
1935 fprintf(stderr,
"Invalid MTU: %d\n", arg);
1936 return EXIT_FAILURE;
1939 if (arg > UINT16_MAX) {
1940 fprintf(stderr,
"MTU too large: %d\n", arg);
1941 return EXIT_FAILURE;
1944 mtu = (uint16_t)arg;
1948 if (strcmp(optarg,
"random") == 0)
1950 else if (strcmp(optarg,
"public") == 0)
1954 "Allowed types: random, public\n");
1955 return EXIT_FAILURE;
1959 if (
str2ba(optarg, &dst_addr) < 0) {
1960 fprintf(stderr,
"Invalid remote address: %s\n",
1962 return EXIT_FAILURE;
1965 dst_addr_given =
true;
1971 perror(
"Invalid adapter");
1972 return EXIT_FAILURE;
1977 fprintf(stderr,
"Invalid option: %c\n", opt);
1978 return EXIT_FAILURE;
1984 return EXIT_SUCCESS;
1993 return EXIT_SUCCESS;
1998 else if (
hci_devba(dev_id, &src_addr) < 0) {
1999 perror(
"Adapter not available");
2000 return EXIT_FAILURE;
2003 if (!dst_addr_given) {
2004 fprintf(stderr,
"Destination address required!\n");
2005 return EXIT_FAILURE;
2013 return EXIT_FAILURE;
2018 return EXIT_FAILURE;
2023 EPOLLIN | EPOLLRDHUP | EPOLLHUP | EPOLLERR,
2025 fprintf(stderr,
"Failed to initialize console\n");
2026 return EXIT_FAILURE;
2030 sigaddset(&mask, SIGINT);
2031 sigaddset(&mask, SIGTERM);
2045 printf(
"\n\nShutting down...\n");
2049 return EXIT_SUCCESS;
#define BT_ERROR_OUT_OF_RANGE
bool gatt_db_attribute_get_char_data(const struct gatt_db_attribute *attrib, uint16_t *handle, uint16_t *value_handle, uint8_t *properties, bt_uuid_t *uuid)
static void cmd_read_value(struct client *cli, char *cmd_str)
static struct client * client_create(int fd, uint16_t mtu)
static void prompt_read_cb(int fd, uint32_t events, void *user_data)
void bt_gatt_client_unref(struct bt_gatt_client *client)
static void unregister_notify_usage(void)
static struct option write_long_value_options[]
static void client_destroy(struct client *cli)
void gatt_db_unref(struct gatt_db *db)
static void signal_cb(int signum, void *user_data)
static void print_service(struct gatt_db_attribute *attr, void *user_data)
static void read_multiple_usage(void)
static void ready_cb(bool success, uint8_t att_ecode, void *user_data)
#define BT_ATT_ERROR_PREPARE_QUEUE_FULL
struct bt_gatt_client * gatt
pointer to a bt_gatt_client structure
bool bt_gatt_client_set_security(struct bt_gatt_client *client, int level)
unsigned int bt_gatt_client_write_value(struct bt_gatt_client *client, uint16_t value_handle, const uint8_t *value, uint16_t length, bt_gatt_client_callback_t callback, void *user_data, bt_gatt_client_destroy_func_t destroy)
bluetooth GATT client structure
uint16_t gatt_db_attribute_get_handle(const struct gatt_db_attribute *attrib)
bool bt_gatt_client_is_ready(struct bt_gatt_client *client)
bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16], bt_att_counter_func_t func, void *user_data)
const bt_uuid_t * gatt_db_attribute_get_type(const struct gatt_db_attribute *attrib)
struct gatt_db * db
pointer to a gatt_db structure
unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client, uint16_t chrc_value_handle, bt_gatt_client_register_callback_t callback, bt_gatt_client_notify_callback_t notify, void *user_data, bt_gatt_client_destroy_func_t destroy)
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
#define BT_ERROR_ALREADY_IN_PROGRESS
static void print_uuid(const bt_uuid_t *uuid)
static void cmd_read_long_value(struct client *cli, char *cmd_str)
static void print_services(struct client *cli)
#define BT_ATT_ERROR_INVALID_OFFSET
bool gatt_db_attribute_get_service_uuid(const struct gatt_db_attribute *attrib, bt_uuid_t *uuid)
static void read_cb(bool success, uint8_t att_ecode, const uint8_t *value, uint16_t length, void *user_data)
void gatt_db_foreach_service_in_range(struct gatt_db *db, const bt_uuid_t *uuid, gatt_db_attribute_cb_t func, void *user_data, uint16_t start_handle, uint16_t end_handle)
static void print_incl(struct gatt_db_attribute *attr, void *user_data)
int hci_devba(int dev_id, bdaddr_t *bdaddr)
static void services_usage(void)
void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
int hci_devid(const char *str)
static void service_changed_cb(uint16_t start_handle, uint16_t end_handle, void *user_data)
static void service_removed_cb(struct gatt_db_attribute *attr, void *user_data)
void gatt_db_service_foreach_char(struct gatt_db_attribute *attrib, gatt_db_attribute_cb_t func, void *user_data)
struct bt_att * att
pointer to a bt_att structure
#define BT_ATT_ERROR_AUTHORIZATION
bool bt_gatt_client_set_service_changed(struct bt_gatt_client *client, bt_gatt_client_service_changed_callback_t callback, void *user_data, bt_gatt_client_destroy_func_t destroy)
int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback, void *user_data, mainloop_destroy_func destroy)
static void cmd_services(struct client *cli, char *cmd_str)
static void read_long_value_usage(void)
int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback, void *user_data, mainloop_destroy_func destroy)
static bool convert_sign_key(char *optarg, uint8_t key[16])
static void print_chrc(struct gatt_db_attribute *attr, void *user_data)
static void notify_cb(uint16_t value_handle, const uint8_t *value, uint16_t length, void *user_data)
struct gatt_db * gatt_db_new(void)
static struct @3 command[]
unsigned int gatt_db_register(struct gatt_db *db, gatt_db_attribute_cb_t service_added, gatt_db_attribute_cb_t service_removed, void *user_data, gatt_db_destroy_func_t destroy)
#define BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN
static void write_value_usage(void)
static void cmd_quit(struct client *cli, char *cmd_str)
void gatt_db_service_foreach_incl(struct gatt_db_attribute *attrib, gatt_db_attribute_cb_t func, void *user_data)
static void read_value_usage(void)
static void bacpy(bdaddr_t *dst, const bdaddr_t *src)
void(* command_func_t)(struct client *cli, char *cmd_str)
#define BT_ATT_ERROR_UNLIKELY
bool bt_att_set_debug(struct bt_att *att, bt_att_debug_func_t callback, void *user_data, bt_att_destroy_func_t destroy)
static bool local_counter(uint32_t *sign_cnt, void *user_data)
bool gatt_db_attribute_get_service_data(const struct gatt_db_attribute *attrib, uint16_t *start_handle, uint16_t *end_handle, bool *primary, bt_uuid_t *uuid)
static const char * ecode_to_string(uint8_t ecode)
static void set_sign_key_usage(void)
static void print_desc(struct gatt_db_attribute *attr, void *user_data)
struct bt_gatt_client * bt_gatt_client_new(struct gatt_db *db, struct bt_att *att, uint16_t mtu)
static void register_notify_cb(uint16_t att_ecode, void *user_data)
static void att_disconnect_cb(int err, void *user_data)
static void set_security_usage(void)
bool bt_gatt_client_set_debug(struct bt_gatt_client *client, bt_gatt_client_debug_func_t callback, void *user_data, bt_gatt_client_destroy_func_t destroy)
static void cmd_set_sign_key(struct client *cli, char *cmd_str)
#define BT_ATT_ERROR_ATTRIBUTE_NOT_LONG
struct bt_att * bt_att_new(int fd, bool ext_signed)
static struct option write_value_options[]
#define BT_ERROR_CCC_IMPROPERLY_CONFIGURED
static void print_services_by_uuid(struct client *cli, const bt_uuid_t *uuid)
void gatt_db_foreach_service(struct gatt_db *db, const bt_uuid_t *uuid, gatt_db_attribute_cb_t func, void *user_data)
static void cmd_write_prepare(struct client *cli, char *cmd_str)
bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client, unsigned int id)
bool bt_att_set_close_on_unref(struct bt_att *att, bool do_close)
bool gatt_db_attribute_get_incl_data(const struct gatt_db_attribute *attrib, uint16_t *handle, uint16_t *start_handle, uint16_t *end_handle)
unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client, uint16_t *handles, uint8_t num_handles, bt_gatt_client_read_callback_t callback, void *user_data, bt_gatt_client_destroy_func_t destroy)
static void gatt_debug_cb(const char *str, void *user_data)
static void cmd_set_security(struct client *cli, char *cmd_str)
#define BT_ATT_ERROR_UNSUPPORTED_GROUP_TYPE
#define BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND
unsigned int bt_gatt_client_write_long_value(struct bt_gatt_client *client, bool reliable, uint16_t value_handle, uint16_t offset, const uint8_t *value, uint16_t length, bt_gatt_client_write_long_callback_t callback, void *user_data, bt_gatt_client_destroy_func_t destroy)
static void cmd_unregister_notify(struct client *cli, char *cmd_str)
static void cmd_write_long_value(struct client *cli, char *cmd_str)
bool gatt_db_attribute_get_service_handles(const struct gatt_db_attribute *attrib, uint16_t *start_handle, uint16_t *end_handle)
bool bt_gatt_client_set_ready_handler(struct bt_gatt_client *client, bt_gatt_client_callback_t callback, void *user_data, bt_gatt_client_destroy_func_t destroy)
static void cmd_write_execute(struct client *cli, char *cmd_str)
#define BT_ATT_ERROR_AUTHENTICATION
unsigned int reliable_session_id
session id
static int l2cap_le_att_connect(bdaddr_t *src, bdaddr_t *dst, uint8_t dst_type, int sec)
int bt_gatt_client_get_security(struct bt_gatt_client *client)
#define BT_SECURITY_MEDIUM
static void write_cb(bool success, uint8_t att_ecode, void *user_data)
#define BT_ATT_ERROR_INVALID_HANDLE
static struct option main_options[]
static void cmd_get_security(struct client *cli, char *cmd_str)
static void att_debug_cb(const char *str, void *user_data)
static void print_services_by_handle(struct client *cli, uint16_t handle)
void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib, gatt_db_attribute_cb_t func, void *user_data)
static void cmd_register_notify(struct client *cli, char *cmd_str)
int str2ba(const char *str, bdaddr_t *ba)
static void cmd_write_value(struct client *cli, char *cmd_str)
#define BT_ATT_ERROR_INSUFFICIENT_RESOURCES
struct gatt_db_attribute * gatt_db_get_attribute(struct gatt_db *db, uint16_t handle)
static void register_notify_usage(void)
static void write_prepare_usage(void)
unsigned int bt_gatt_client_write_execute(struct bt_gatt_client *client, unsigned int id, bt_gatt_client_callback_t callback, void *user_data, bt_gatt_client_destroy_func_t destroy)
static void service_added_cb(struct gatt_db_attribute *attr, void *user_data)
unsigned int bt_gatt_client_write_without_response(struct bt_gatt_client *client, uint16_t value_handle, bool signed_write, const uint8_t *value, uint16_t length)
static void write_long_value_usage(void)
static void print_prompt(void)
static void cmd_help(struct client *cli, char *cmd_str)
static bool parse_args(char *str, int expected_argc, char **argv, int *argc)
unsigned int bt_gatt_client_prepare_write(struct bt_gatt_client *client, unsigned int id, uint16_t value_handle, uint16_t offset, const uint8_t *value, uint16_t length, bt_gatt_client_write_long_callback_t callback, void *user_data, bt_gatt_client_destroy_func_t destroy)
#define BT_ATT_ERROR_INVALID_PDU
int ba2str(const bdaddr_t *ba, char *str)
static void log_service_event(struct gatt_db_attribute *attr, const char *str)
#define BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE
#define BT_ATT_ERROR_READ_NOT_PERMITTED
#define BT_ATT_ERROR_WRITE_NOT_PERMITTED
#define BT_ATT_ERROR_REQUEST_NOT_SUPPORTED
static void read_multiple_cb(bool success, uint8_t att_ecode, const uint8_t *value, uint16_t length, void *user_data)
struct gatt_db_service * service
unsigned int bt_gatt_client_read_long_value(struct bt_gatt_client *client, uint16_t value_handle, uint16_t offset, bt_gatt_client_read_callback_t callback, void *user_data, bt_gatt_client_destroy_func_t destroy)
unsigned int bt_att_register_disconnect(struct bt_att *att, bt_att_disconnect_func_t callback, void *user_data, bt_att_destroy_func_t destroy)
void bt_att_unref(struct bt_att *att)
static struct option write_prepare_options[]
static void write_long_cb(bool success, bool reliable_error, uint8_t att_ecode, void *user_data)
static void cmd_read_multiple(struct client *cli, char *cmd_str)
unsigned int bt_gatt_client_read_value(struct bt_gatt_client *client, uint16_t value_handle, bt_gatt_client_read_callback_t callback, void *user_data, bt_gatt_client_destroy_func_t destroy)
static void write_execute_usage(void)
int main(int argc, char *argv[])
#define BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION
bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id)
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)