ble_gatt_client
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
btgattclient.c
Go to the documentation of this file.
1 
14 /*
15  * BlueZ - Bluetooth protocol stack for Linux
16  *
17  * Copyright (C) 2014 Google Inc.
18  *
19  *
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License as published by
22  * the Free Software Foundation; either version 2 of the License, or
23  * (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33  *
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 
40 #include <stdio.h>
41 #include <stdbool.h>
42 #include <stdint.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <getopt.h>
46 #include <limits.h>
47 #include <errno.h>
48 
49 #include "bluetooth.h"
50 #include "hci.h"
51 #include "hci_lib.h"
52 #include "l2cap.h"
53 #include "uuid.h"
54 
55 #include "mainloop.h"
56 #include "util.h"
57 #include "att.h"
58 #include "queue.h"
59 #include "gatt-db.h"
60 #include "gatt-client.h"
61 
62 #define ATT_CID 4
63 
64 #define PRLOG(...) \
65  printf(__VA_ARGS__); print_prompt();
66 
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"
75 
76 static bool verbose = false;
77 
81 struct client {
83  int fd;
85  struct bt_att *att;
87  struct gatt_db *db;
91  unsigned int reliable_session_id;
92 };
93 
97 static void print_prompt(void)
98 {
99  printf(COLOR_BLUE "[GATT client]" COLOR_OFF "# ");
100  fflush(stdout);
101 }
102 
109 static const char *ecode_to_string(uint8_t ecode)
110 {
111  switch (ecode) {
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";
152  default:
153  return "Unknown error type";
154  }
155 }
156 
163 static void att_disconnect_cb(int err, void *user_data)
164 {
165  printf("Device disconnected: %s\n", strerror(err));
166 
167  mainloop_quit();
168 }
169 
177 static void att_debug_cb(const char *str, void *user_data)
178 {
179  const char *prefix = user_data;
180  PRLOG(COLOR_BOLDGRAY "%s" COLOR_BOLDWHITE "%s\n" COLOR_OFF, prefix, str);
181 }
182 
190 static void gatt_debug_cb(const char *str, void *user_data)
191 {
192  const char *prefix = user_data;
193 
194  PRLOG(COLOR_GREEN "%s%s\n" COLOR_OFF, prefix, str);
195 }
196 
197 static void ready_cb(bool success, uint8_t att_ecode, void *user_data);
198 static void service_changed_cb(uint16_t start_handle, uint16_t end_handle,
199  void *user_data);
200 
207 static void log_service_event(struct gatt_db_attribute *attr, const char *str)
208 {
209  char uuid_str[MAX_LEN_UUID_STR];
210  bt_uuid_t uuid;
211  uint16_t start, end;
212 
214  bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
215 
216  gatt_db_attribute_get_service_handles(attr, &start, &end);
217 
218  PRLOG("%s - UUID: %s start: 0x%04x end: 0x%04x\n", str, uuid_str,
219  start, end);
220 }
221 
228 static void service_added_cb(struct gatt_db_attribute *attr, void *user_data)
229 {
230  log_service_event(attr, "Service Added");
231 }
232 
239 static void service_removed_cb(struct gatt_db_attribute *attr, void *user_data)
240 {
241  log_service_event(attr, "Service Removed");
242 }
243 
251 static struct client *client_create(int fd, uint16_t mtu)
252 {
253  struct client *cli;
254 
255  cli = new0(struct client, 1);
256  if (!cli) {
257  fprintf(stderr, "Failed to allocate memory for client\n");
258  return NULL;
259  }
260 
261  cli->att = bt_att_new(fd, false);
262  if (!cli->att) {
263  fprintf(stderr, "Failed to initialze ATT transport layer\n");
264  bt_att_unref(cli->att);
265  free(cli);
266  return NULL;
267  }
268 
269  if (!bt_att_set_close_on_unref(cli->att, true)) {
270  fprintf(stderr, "Failed to set up ATT transport layer\n");
271  bt_att_unref(cli->att);
272  free(cli);
273  return NULL;
274  }
275 
277  NULL)) {
278  fprintf(stderr, "Failed to set ATT disconnect handler\n");
279  bt_att_unref(cli->att);
280  free(cli);
281  return NULL;
282  }
283 
284  cli->fd = fd;
285  cli->db = gatt_db_new();
286  if (!cli->db) {
287  fprintf(stderr, "Failed to create GATT database\n");
288  bt_att_unref(cli->att);
289  free(cli);
290  return NULL;
291  }
292 
293  cli->gatt = bt_gatt_client_new(cli->db, cli->att, mtu);
294  if (!cli->gatt) {
295  fprintf(stderr, "Failed to create GATT client\n");
296  gatt_db_unref(cli->db);
297  bt_att_unref(cli->att);
298  free(cli);
299  return NULL;
300  }
301 
303  NULL, NULL);
304 
305  if (verbose) {
306  bt_att_set_debug(cli->att, att_debug_cb, "att: ", NULL);
308  NULL);
309  }
310 
313  NULL);
314 
315  /* bt_gatt_client already holds a reference */
316  gatt_db_unref(cli->db);
317 
318  return cli;
319 }
320 
326 static void client_destroy(struct client *cli)
327 {
329  bt_att_unref(cli->att);
330  free(cli);
331 }
332 
338 static void print_uuid(const bt_uuid_t *uuid)
339 {
340  char uuid_str[MAX_LEN_UUID_STR];
341  bt_uuid_t uuid128;
342 
343  bt_uuid_to_uuid128(uuid, &uuid128);
344  bt_uuid_to_string(&uuid128, uuid_str, sizeof(uuid_str));
345 
346  printf("%s\n", uuid_str);
347 }
348 
355 static void print_incl(struct gatt_db_attribute *attr, void *user_data)
356 {
357  struct client *cli = user_data;
358  uint16_t handle, start, end;
359  struct gatt_db_attribute *service;
360  bt_uuid_t uuid;
361 
362  if (!gatt_db_attribute_get_incl_data(attr, &handle, &start, &end))
363  return;
364 
365  service = gatt_db_get_attribute(cli->db, start);
366  if (!service)
367  return;
368 
369  gatt_db_attribute_get_service_uuid(service, &uuid);
370 
371  printf("\t " COLOR_GREEN "include" COLOR_OFF " - handle: "
372  "0x%04x, - start: 0x%04x, end: 0x%04x,"
373  "uuid: ", handle, start, end);
374  print_uuid(&uuid);
375 }
376 
383 static void print_desc(struct gatt_db_attribute *attr, void *user_data)
384 {
385  printf("\t\t " COLOR_MAGENTA "descr" COLOR_OFF
386  " - handle: 0x%04x, uuid: ",
389 }
390 
397 static void print_chrc(struct gatt_db_attribute *attr, void *user_data)
398 {
399  uint16_t handle, value_handle;
400  uint8_t properties;
401  bt_uuid_t uuid;
402 
403  if (!gatt_db_attribute_get_char_data(attr, &handle,
404  &value_handle,
405  &properties,
406  &uuid))
407  return;
408 
409  printf("\t " COLOR_YELLOW "charac" COLOR_OFF
410  " - start: 0x%04x, value: 0x%04x, "
411  "props: 0x%02x, uuid: ",
412  handle, value_handle, properties);
413  print_uuid(&uuid);
414 
416 }
417 
424 static void print_service(struct gatt_db_attribute *attr, void *user_data)
425 {
426  struct client *cli = user_data;
427  uint16_t start, end;
428  bool primary;
429  bt_uuid_t uuid;
430 
431  if (!gatt_db_attribute_get_service_data(attr, &start, &end, &primary,
432  &uuid))
433  return;
434 
435  printf(COLOR_RED "service" COLOR_OFF " - start: 0x%04x, "
436  "end: 0x%04x, type: %s, uuid: ",
437  start, end, primary ? "primary" : "secondary");
438  print_uuid(&uuid);
439 
442 
443  printf("\n");
444 }
445 
451 static void print_services(struct client *cli)
452 {
453  printf("\n");
454 
455  gatt_db_foreach_service(cli->db, NULL, print_service, cli);
456 }
457 
464 static void print_services_by_uuid(struct client *cli, const bt_uuid_t *uuid)
465 {
466  printf("\n");
467 
468  gatt_db_foreach_service(cli->db, uuid, print_service, cli);
469 }
470 
477 static void print_services_by_handle(struct client *cli, uint16_t handle)
478 {
479  printf("\n");
480 
481  /* TODO: Filter by handle */
482  gatt_db_foreach_service(cli->db, NULL, print_service, cli);
483 }
484 
492 static void ready_cb(bool success, uint8_t att_ecode, void *user_data)
493 {
494  struct client *cli = user_data;
495 
496  if (!success) {
497  PRLOG("GATT discovery procedures failed - error code: 0x%02x\n",
498  att_ecode);
499  return;
500  }
501 
502  PRLOG("GATT discovery procedures complete\n");
503 
504  print_services(cli);
505  print_prompt();
506 }
507 
515 static void service_changed_cb(uint16_t start_handle, uint16_t end_handle,
516  void *user_data)
517 {
518  struct client *cli = user_data;
519 
520  printf("\nService Changed handled - start: 0x%04x end: 0x%04x\n",
521  start_handle, end_handle);
522 
524  start_handle, end_handle);
525  print_prompt();
526 }
527 
531 static void services_usage(void)
532 {
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"
537  "e.g.:\n"
538  "\tservices\n\tservices -u 0x180d\n\tservices -a 0x0009\n");
539 }
540 
550 static bool parse_args(char *str, int expected_argc, char **argv, int *argc)
551 {
552  char **ap;
553 
554  for (ap = argv; (*ap = strsep(&str, " \t")) != NULL;) {
555  if (**ap == '\0')
556  continue;
557 
558  (*argc)++;
559  ap++;
560 
561  if (*argc > expected_argc)
562  return false;
563  }
564 
565  return true;
566 }
567 
575 static void cmd_services(struct client *cli, char *cmd_str)
576 {
577  char *argv[3];
578  int argc = 0;
579 
580  if (!bt_gatt_client_is_ready(cli->gatt)) {
581  printf("GATT client not initialized\n");
582  return;
583  }
584 
585  if (!parse_args(cmd_str, 2, argv, &argc)) {
586  services_usage();
587  return;
588  }
589 
590  if (!argc) {
591  print_services(cli);
592  return;
593  }
594 
595  if (argc != 2) {
596  services_usage();
597  return;
598  }
599 
600  if (!strcmp(argv[0], "-u") || !strcmp(argv[0], "--uuid")) {
601  bt_uuid_t tmp, uuid;
602 
603  if (bt_string_to_uuid(&tmp, argv[1]) < 0) {
604  printf("Invalid UUID: %s\n", argv[1]);
605  return;
606  }
607 
608  bt_uuid_to_uuid128(&tmp, &uuid);
609 
610  print_services_by_uuid(cli, &uuid);
611  } else if (!strcmp(argv[0], "-a") || !strcmp(argv[0], "--handle")) {
612  uint16_t handle;
613  char *endptr = NULL;
614 
615  handle = strtol(argv[1], &endptr, 0);
616  if (!endptr || *endptr != '\0') {
617  printf("Invalid start handle: %s\n", argv[1]);
618  return;
619  }
620 
621  print_services_by_handle(cli, handle);
622  } else
623  services_usage();
624 }
625 
629 static void read_multiple_usage(void)
630 {
631  printf("Usage: read-multiple <handle_1> <handle_2> ...\n");
632 }
633 
643 static void read_multiple_cb(bool success, uint8_t att_ecode,
644  const uint8_t *value, uint16_t length,
645  void *user_data)
646 {
647  int i;
648 
649  if (!success) {
650  PRLOG("\nRead multiple request failed: 0x%02x\n", att_ecode);
651  return;
652  }
653 
654  printf("\nRead multiple value (%u bytes):", length);
655 
656  for (i = 0; i < length; i++)
657  printf("%02x ", value[i]);
658 
659  PRLOG("\n");
660 }
661 
668 static void cmd_read_multiple(struct client *cli, char *cmd_str)
669 {
670  int argc = 0;
671  uint16_t *value;
672  char *argv[512];
673  int i;
674  char *endptr = NULL;
675 
676  if (!bt_gatt_client_is_ready(cli->gatt)) {
677  printf("GATT client not initialized\n");
678  return;
679  }
680 
681  if (!parse_args(cmd_str, sizeof(argv), argv, &argc) || argc < 2) {
683  return;
684  }
685 
686  value = malloc(sizeof(uint16_t) * argc);
687  if (!value) {
688  printf("Failed to construct value\n");
689  return;
690  }
691 
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]);
696  free(value);
697  return;
698  }
699  }
700 
701  if (!bt_gatt_client_read_multiple(cli->gatt, value, argc,
702  read_multiple_cb, NULL, NULL))
703  printf("Failed to initiate read multiple procedure\n");
704 
705  free(value);
706 }
707 
711 static void read_value_usage(void)
712 {
713  printf("Usage: read-value <value_handle>\n");
714 }
715 
725 static void read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
726  uint16_t length, void *user_data)
727 {
728  int i;
729 
730  if (!success) {
731  PRLOG("\nRead request failed: %s (0x%02x)\n",
732  ecode_to_string(att_ecode), att_ecode);
733  return;
734  }
735 
736  printf("\nRead value");
737 
738  if (length == 0) {
739  PRLOG(": 0 bytes\n");
740  return;
741  }
742 
743  printf(" (%u bytes): ", length);
744 
745  for (i = 0; i < length; i++)
746  printf("%02x ", value[i]);
747 
748  PRLOG("\n");
749 }
750 
757 static void cmd_read_value(struct client *cli, char *cmd_str)
758 {
759  char *argv[2];
760  int argc = 0;
761  uint16_t handle;
762  char *endptr = NULL;
763 
764  if (!bt_gatt_client_is_ready(cli->gatt)) {
765  printf("GATT client not initialized\n");
766  return;
767  }
768 
769  if (!parse_args(cmd_str, 1, argv, &argc) || argc != 1) {
771  return;
772  }
773 
774  handle = strtol(argv[0], &endptr, 0);
775  if (!endptr || *endptr != '\0' || !handle) {
776  printf("Invalid value handle: %s\n", argv[0]);
777  return;
778  }
779 
780  if (!bt_gatt_client_read_value(cli->gatt, handle, read_cb,
781  NULL, NULL))
782  printf("Failed to initiate read value procedure\n");
783 }
784 
788 static void read_long_value_usage(void)
789 {
790  printf("Usage: read-long-value <value_handle> <offset>\n");
791 }
792 
799 static void cmd_read_long_value(struct client *cli, char *cmd_str)
800 {
801  char *argv[3];
802  int argc = 0;
803  uint16_t handle;
804  uint16_t offset;
805  char *endptr = NULL;
806 
807  if (!bt_gatt_client_is_ready(cli->gatt)) {
808  printf("GATT client not initialized\n");
809  return;
810  }
811 
812  if (!parse_args(cmd_str, 2, argv, &argc) || argc != 2) {
814  return;
815  }
816 
817  handle = strtol(argv[0], &endptr, 0);
818  if (!endptr || *endptr != '\0' || !handle) {
819  printf("Invalid value handle: %s\n", argv[0]);
820  return;
821  }
822 
823  endptr = NULL;
824  offset = strtol(argv[1], &endptr, 0);
825  if (!endptr || *endptr != '\0') {
826  printf("Invalid offset: %s\n", argv[1]);
827  return;
828  }
829 
830  if (!bt_gatt_client_read_long_value(cli->gatt, handle, offset, read_cb,
831  NULL, NULL))
832  printf("Failed to initiate read long value procedure\n");
833 }
834 
838 static void write_value_usage(void)
839 {
840  printf("Usage: write-value [options] <value_handle> <value>\n"
841  "Options:\n"
842  "\t-w, --without-response\tWrite without response\n"
843  "\t-s, --signed-write\tSigned write command\n"
844  "e.g.:\n"
845  "\twrite-value 0x0001 00 01 00\n");
846 }
847 
848 static struct option write_value_options[] = {
849  { "without-response", 0, 0, 'w' },
850  { "signed-write", 0, 0, 's' },
851  { }
852 };
853 
861 static void write_cb(bool success, uint8_t att_ecode, void *user_data)
862 {
863  if (success) {
864  PRLOG("\nWrite successful\n");
865  } else {
866  PRLOG("\nWrite failed: %s (0x%02x)\n",
867  ecode_to_string(att_ecode), att_ecode);
868  }
869 }
870 
877 static void cmd_write_value(struct client *cli, char *cmd_str)
878 {
879  int opt, i;
880  char *argvbuf[516];
881  char **argv = argvbuf;
882  int argc = 1;
883  uint16_t handle;
884  char *endptr = NULL;
885  int length;
886  uint8_t *value = NULL;
887  bool without_response = false;
888  bool signed_write = false;
889 
890  if (!bt_gatt_client_is_ready(cli->gatt)) {
891  printf("GATT client not initialized\n");
892  return;
893  }
894 
895  if (!parse_args(cmd_str, 514, argv + 1, &argc)) {
896  printf("Too many arguments\n");
898  return;
899  }
900 
901  optind = 0;
902  argv[0] = "write-value";
903  while ((opt = getopt_long(argc, argv, "+ws", write_value_options,
904  NULL)) != -1) {
905  switch (opt) {
906  case 'w':
907  without_response = true;
908  break;
909  case 's':
910  signed_write = true;
911  break;
912  default:
914  return;
915  }
916  }
917 
918  argc -= optind;
919  argv += optind;
920 
921  if (argc < 1) {
923  return;
924  }
925 
926  handle = strtol(argv[0], &endptr, 0);
927  if (!endptr || *endptr != '\0' || !handle) {
928  printf("Invalid handle: %s\n", argv[0]);
929  return;
930  }
931 
932  length = argc - 1;
933 
934  if (length > 0) {
935  if (length > UINT16_MAX) {
936  printf("Write value too long\n");
937  return;
938  }
939 
940  value = malloc(length);
941  if (!value) {
942  printf("Failed to construct write value\n");
943  return;
944  }
945 
946  for (i = 1; i < argc; i++) {
947  if (strlen(argv[i]) != 2) {
948  printf("Invalid value byte: %s\n",
949  argv[i]);
950  goto done;
951  }
952 
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",
957  argv[i]);
958  goto done;
959  }
960  }
961  }
962 
963  if (without_response) {
965  signed_write, value, length)) {
966  printf("Failed to initiate write without response "
967  "procedure\n");
968  goto done;
969  }
970 
971  printf("Write command sent\n");
972  goto done;
973  }
974 
975  if (!bt_gatt_client_write_value(cli->gatt, handle, value, length,
976  write_cb,
977  NULL, NULL))
978  printf("Failed to initiate write procedure\n");
979 
980 done:
981  free(value);
982 }
983 
987 static void write_long_value_usage(void)
988 {
989  printf("Usage: write-long-value [options] <value_handle> <offset> "
990  "<value>\n"
991  "Options:\n"
992  "\t-r, --reliable-write\tReliable write\n"
993  "e.g.:\n"
994  "\twrite-long-value 0x0001 0 00 01 00\n");
995 }
996 
997 static struct option write_long_value_options[] = {
998  { "reliable-write", 0, 0, 'r' },
999  { }
1000 };
1001 
1010 static void write_long_cb(bool success, bool reliable_error, uint8_t att_ecode,
1011  void *user_data)
1012 {
1013  if (success) {
1014  PRLOG("Write successful\n");
1015  } else if (reliable_error) {
1016  PRLOG("Reliable write not verified\n");
1017  } else {
1018  PRLOG("\nWrite failed: %s (0x%02x)\n",
1019  ecode_to_string(att_ecode), att_ecode);
1020  }
1021 }
1022 
1029 static void cmd_write_long_value(struct client *cli, char *cmd_str)
1030 {
1031  int opt, i;
1032  char *argvbuf[516];
1033  char **argv = argvbuf;
1034  int argc = 1;
1035  uint16_t handle;
1036  uint16_t offset;
1037  char *endptr = NULL;
1038  int length;
1039  uint8_t *value = NULL;
1040  bool reliable_writes = false;
1041 
1042  if (!bt_gatt_client_is_ready(cli->gatt)) {
1043  printf("GATT client not initialized\n");
1044  return;
1045  }
1046 
1047  if (!parse_args(cmd_str, 514, argv + 1, &argc)) {
1048  printf("Too many arguments\n");
1050  return;
1051  }
1052 
1053  optind = 0;
1054  argv[0] = "write-long-value";
1055  while ((opt = getopt_long(argc, argv, "+r", write_long_value_options,
1056  NULL)) != -1) {
1057  switch (opt) {
1058  case 'r':
1059  reliable_writes = true;
1060  break;
1061  default:
1063  return;
1064  }
1065  }
1066 
1067  argc -= optind;
1068  argv += optind;
1069 
1070  if (argc < 2) {
1072  return;
1073  }
1074 
1075  handle = strtol(argv[0], &endptr, 0);
1076  if (!endptr || *endptr != '\0' || !handle) {
1077  printf("Invalid handle: %s\n", argv[0]);
1078  return;
1079  }
1080 
1081  endptr = NULL;
1082  offset = strtol(argv[1], &endptr, 0);
1083  if (!endptr || *endptr != '\0' || errno == ERANGE) {
1084  printf("Invalid offset: %s\n", argv[1]);
1085  return;
1086  }
1087 
1088  length = argc - 2;
1089 
1090  if (length > 0) {
1091  if (length > UINT16_MAX) {
1092  printf("Write value too long\n");
1093  return;
1094  }
1095 
1096  value = malloc(length);
1097  if (!value) {
1098  printf("Failed to construct write value\n");
1099  return;
1100  }
1101 
1102  for (i = 2; i < argc; i++) {
1103  if (strlen(argv[i]) != 2) {
1104  printf("Invalid value byte: %s\n",
1105  argv[i]);
1106  free(value);
1107  return;
1108  }
1109 
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",
1114  argv[i]);
1115  free(value);
1116  return;
1117  }
1118  }
1119  }
1120 
1121  if (!bt_gatt_client_write_long_value(cli->gatt, reliable_writes, handle,
1122  offset, value, length,
1123  write_long_cb,
1124  NULL, NULL))
1125  printf("Failed to initiate long write procedure\n");
1126 
1127  free(value);
1128 }
1129 
1133 static void write_prepare_usage(void)
1134 {
1135  printf("Usage: write-prepare [options] <value_handle> <offset> "
1136  "<value>\n"
1137  "Options:\n"
1138  "\t-s, --session-id\tSession id\n"
1139  "e.g.:\n"
1140  "\twrite-prepare -s 1 0x0001 00 01 00\n");
1141 }
1142 
1143 static struct option write_prepare_options[] = {
1144  { "session-id", 1, 0, 's' },
1145  { }
1146 };
1147 
1154 static void cmd_write_prepare(struct client *cli, char *cmd_str)
1155 {
1156  int opt, i;
1157  char *argvbuf[516];
1158  char **argv = argvbuf;
1159  int argc = 0;
1160  unsigned int id = 0;
1161  uint16_t handle;
1162  uint16_t offset;
1163  char *endptr = NULL;
1164  unsigned int length;
1165  uint8_t *value = NULL;
1166 
1167  if (!bt_gatt_client_is_ready(cli->gatt)) {
1168  printf("GATT client not initialized\n");
1169  return;
1170  }
1171 
1172  if (!parse_args(cmd_str, 514, argv + 1, &argc)) {
1173  printf("Too many arguments\n");
1175  return;
1176  }
1177 
1178  /* Add command name for getopt_long */
1179  argc++;
1180  argv[0] = "write-prepare";
1181 
1182  optind = 0;
1183  while ((opt = getopt_long(argc, argv , "s:", write_prepare_options,
1184  NULL)) != -1) {
1185  switch (opt) {
1186  case 's':
1187  if (!optarg) {
1189  return;
1190  }
1191 
1192  id = atoi(optarg);
1193 
1194  break;
1195  default:
1197  return;
1198  }
1199  }
1200 
1201  argc -= optind;
1202  argv += optind;
1203 
1204  if (argc < 3) {
1206  return;
1207  }
1208 
1209  if (cli->reliable_session_id != id) {
1210  printf("Session id != Ongoing session id (%u!=%u)\n", id,
1211  cli->reliable_session_id);
1212  return;
1213  }
1214 
1215  handle = strtol(argv[0], &endptr, 0);
1216  if (!endptr || *endptr != '\0' || !handle) {
1217  printf("Invalid handle: %s\n", argv[0]);
1218  return;
1219  }
1220 
1221  endptr = NULL;
1222  offset = strtol(argv[1], &endptr, 0);
1223  if (!endptr || *endptr != '\0' || errno == ERANGE) {
1224  printf("Invalid offset: %s\n", argv[1]);
1225  return;
1226  }
1227 
1228  /*
1229  * First two arguments are handle and offset. What remains is the value
1230  * length
1231  */
1232  length = argc - 2;
1233 
1234  if (length == 0)
1235  goto done;
1236 
1237  if (length > UINT16_MAX) {
1238  printf("Write value too long\n");
1239  return;
1240  }
1241 
1242  value = malloc(length);
1243  if (!value) {
1244  printf("Failed to allocate memory for value\n");
1245  return;
1246  }
1247 
1248  for (i = 2; i < argc; i++) {
1249  if (strlen(argv[i]) != 2) {
1250  printf("Invalid value byte: %s\n", argv[i]);
1251  free(value);
1252  return;
1253  }
1254 
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]);
1258  free(value);
1259  return;
1260  }
1261  }
1262 
1263 done:
1264  cli->reliable_session_id =
1266  handle, offset,
1267  value, length,
1268  write_long_cb, NULL,
1269  NULL);
1270  if (!cli->reliable_session_id)
1271  printf("Failed to proceed prepare write\n");
1272  else
1273  printf("Prepare write success.\n"
1274  "Session id: %d to be used on next write\n",
1275  cli->reliable_session_id);
1276 
1277  free(value);
1278 }
1279 
1283 static void write_execute_usage(void)
1284 {
1285  printf("Usage: write-execute <session_id> <execute>\n"
1286  "e.g.:\n"
1287  "\twrite-execute 1 0\n");
1288 }
1289 
1296 static void cmd_write_execute(struct client *cli, char *cmd_str)
1297 {
1298  char *argvbuf[516];
1299  char **argv = argvbuf;
1300  int argc = 0;
1301  char *endptr = NULL;
1302  unsigned int session_id;
1303  bool execute;
1304 
1305  if (!bt_gatt_client_is_ready(cli->gatt)) {
1306  printf("GATT client not initialized\n");
1307  return;
1308  }
1309 
1310  if (!parse_args(cmd_str, 514, argv, &argc)) {
1311  printf("Too many arguments\n");
1313  return;
1314  }
1315 
1316  if (argc < 2) {
1318  return;
1319  }
1320 
1321  session_id = strtol(argv[0], &endptr, 0);
1322  if (!endptr || *endptr != '\0') {
1323  printf("Invalid session id: %s\n", argv[0]);
1324  return;
1325  }
1326 
1327  if (session_id != cli->reliable_session_id) {
1328  printf("Invalid session id: %u != %u\n", session_id,
1329  cli->reliable_session_id);
1330  return;
1331  }
1332 
1333  execute = !!strtol(argv[1], &endptr, 0);
1334  if (!endptr || *endptr != '\0') {
1335  printf("Invalid execute: %s\n", argv[1]);
1336  return;
1337  }
1338 
1339  if (execute) {
1340  if (!bt_gatt_client_write_execute(cli->gatt, session_id,
1341  write_cb, NULL, NULL))
1342  printf("Failed to proceed write execute\n");
1343  } else {
1344  bt_gatt_client_cancel(cli->gatt, session_id);
1345  }
1346 
1347  cli->reliable_session_id = 0;
1348 }
1349 
1353 static void register_notify_usage(void)
1354 {
1355  printf("Usage: register-notify <chrc value handle>\n");
1356 }
1357 
1366 static void notify_cb(uint16_t value_handle, const uint8_t *value,
1367  uint16_t length, void *user_data)
1368 {
1369  int i;
1370 
1371  printf("\n\tHandle Value Not/Ind: 0x%04x - ", value_handle);
1372 
1373  if (length == 0) {
1374  PRLOG("(0 bytes)\n");
1375  return;
1376  }
1377 
1378  printf("(%u bytes): ", length);
1379 
1380  for (i = 0; i < length; i++)
1381  printf("%02x ", value[i]);
1382 
1383  PRLOG("\n");
1384 }
1385 
1392 static void register_notify_cb(uint16_t att_ecode, void *user_data)
1393 {
1394  if (att_ecode) {
1395  PRLOG("Failed to register notify handler "
1396  "- error code: 0x%02x\n", att_ecode);
1397  return;
1398  }
1399 
1400  PRLOG("Registered notify handler!");
1401 }
1402 
1409 static void cmd_register_notify(struct client *cli, char *cmd_str)
1410 {
1411  char *argv[2];
1412  int argc = 0;
1413  uint16_t value_handle;
1414  unsigned int id;
1415  char *endptr = NULL;
1416 
1417  if (!bt_gatt_client_is_ready(cli->gatt)) {
1418  printf("GATT client not initialized\n");
1419  return;
1420  }
1421 
1422  if (!parse_args(cmd_str, 1, argv, &argc) || argc != 1) {
1424  return;
1425  }
1426 
1427  value_handle = strtol(argv[0], &endptr, 0);
1428  if (!endptr || *endptr != '\0' || !value_handle) {
1429  printf("Invalid value handle: %s\n", argv[0]);
1430  return;
1431  }
1432 
1433  id = bt_gatt_client_register_notify(cli->gatt, value_handle,
1435  notify_cb, NULL, NULL);
1436  if (!id) {
1437  printf("Failed to register notify handler\n");
1438  return;
1439  }
1440 
1441  PRLOG("Registering notify handler with id: %u\n", id);
1442 }
1443 
1447 static void unregister_notify_usage(void)
1448 {
1449  printf("Usage: unregister-notify <notify id>\n");
1450 }
1451 
1458 static void cmd_unregister_notify(struct client *cli, char *cmd_str)
1459 {
1460  char *argv[2];
1461  int argc = 0;
1462  unsigned int id;
1463  char *endptr = NULL;
1464 
1465  if (!bt_gatt_client_is_ready(cli->gatt)) {
1466  printf("GATT client not initialized\n");
1467  return;
1468  }
1469 
1470  if (!parse_args(cmd_str, 1, argv, &argc) || argc != 1) {
1472  return;
1473  }
1474 
1475  id = strtol(argv[0], &endptr, 0);
1476  if (!endptr || *endptr != '\0' || !id) {
1477  printf("Invalid notify id: %s\n", argv[0]);
1478  return;
1479  }
1480 
1481  if (!bt_gatt_client_unregister_notify(cli->gatt, id)) {
1482  printf("Failed to unregister notify handler with id: %u\n", id);
1483  return;
1484  }
1485 
1486  printf("Unregistered notify handler with id: %u\n", id);
1487 }
1488 
1492 static void set_security_usage(void)
1493 {
1494  printf("Usage: set_security <level>\n"
1495  "level: 1-3\n"
1496  "e.g.:\n"
1497  "\tset-sec-level 2\n");
1498 }
1499 
1506 static void cmd_set_security(struct client *cli, char *cmd_str)
1507 {
1508  char *argvbuf[1];
1509  char **argv = argvbuf;
1510  int argc = 0;
1511  char *endptr = NULL;
1512  int level;
1513 
1514  if (!bt_gatt_client_is_ready(cli->gatt)) {
1515  printf("GATT client not initialized\n");
1516  return;
1517  }
1518 
1519  if (!parse_args(cmd_str, 1, argv, &argc)) {
1520  printf("Too many arguments\n");
1522  return;
1523  }
1524 
1525  if (argc < 1) {
1527  return;
1528  }
1529 
1530  level = strtol(argv[0], &endptr, 0);
1531  if (!endptr || *endptr != '\0' || level < 1 || level > 3) {
1532  printf("Invalid level: %s\n", argv[0]);
1533  return;
1534  }
1535 
1536  if (!bt_gatt_client_set_security(cli->gatt, level))
1537  printf("Could not set sec level\n");
1538  else
1539  printf("Setting security level %d success\n", level);
1540 }
1541 
1548 static void cmd_get_security(struct client *cli, char *cmd_str)
1549 {
1550  int level;
1551 
1552  if (!bt_gatt_client_is_ready(cli->gatt)) {
1553  printf("GATT client not initialized\n");
1554  return;
1555  }
1556 
1557  level = bt_gatt_client_get_security(cli->gatt);
1558  if (level < 0)
1559  printf("Could not set sec level\n");
1560  else
1561  printf("Security level: %u\n", level);
1562 }
1563 
1571 static bool convert_sign_key(char *optarg, uint8_t key[16])
1572 {
1573  int i;
1574 
1575  if (strlen(optarg) != 32) {
1576  printf("sign-key length is invalid\n");
1577  return false;
1578  }
1579 
1580  for (i = 0; i < 16; i++) {
1581  if (sscanf(optarg + (i * 2), "%2hhx", &key[i]) != 1)
1582  return false;
1583  }
1584 
1585  return true;
1586 }
1587 
1591 static void set_sign_key_usage(void)
1592 {
1593  printf("Usage: set-sign-key [options]\nOptions:\n"
1594  "\t -c, --sign-key <csrk>\tCSRK\n"
1595  "e.g.:\n"
1596  "\tset-sign-key -c D8515948451FEA320DC05A2E88308188\n");
1597 }
1598 
1606 static bool local_counter(uint32_t *sign_cnt, void *user_data)
1607 {
1608  static uint32_t cnt = 0;
1609 
1610  *sign_cnt = cnt++;
1611 
1612  return true;
1613 }
1614 
1621 static void cmd_set_sign_key(struct client *cli, char *cmd_str)
1622 {
1623  char *argv[3];
1624  int argc = 0;
1625  uint8_t key[16];
1626 
1627  memset(key, 0, 16);
1628 
1629  if (!parse_args(cmd_str, 2, argv, &argc)) {
1631  return;
1632  }
1633 
1634  if (argc != 2) {
1636  return;
1637  }
1638 
1639  if (!strcmp(argv[0], "-c") || !strcmp(argv[0], "--sign-key")) {
1640  if (convert_sign_key(argv[1], key))
1641  bt_att_set_local_key(cli->att, key, local_counter, cli);
1642  } else
1644 }
1645 
1646 static void cmd_help(struct client *cli, char *cmd_str);
1647 
1648 static void cmd_quit(struct client *cli, char *cmd_str){
1649  mainloop_quit();
1650 }
1651 
1652 
1653 typedef void (*command_func_t)(struct client *cli, char *cmd_str);
1654 
1655 static struct {
1656  char *cmd;
1658  char *doc;
1659 } command[] = {
1660  { "help", cmd_help, "\tDisplay help message" },
1661  { "services", cmd_services, "\tShow discovered services" },
1662  { "read-value", cmd_read_value,
1663  "\tRead a characteristic or descriptor value" },
1664  { "read-long-value", cmd_read_long_value,
1665  "\tRead a long characteristic or desctriptor value" },
1666  { "read-multiple", cmd_read_multiple, "\tRead Multiple" },
1667  { "write-value", cmd_write_value,
1668  "\tWrite a characteristic or descriptor value" },
1669  { "write-long-value", cmd_write_long_value,
1670  "Write long characteristic or descriptor value" },
1671  { "write-prepare", cmd_write_prepare,
1672  "\tWrite prepare characteristic or descriptor value" },
1673  { "write-execute", cmd_write_execute,
1674  "\tExecute already prepared write" },
1675  { "register-notify", cmd_register_notify,
1676  "\tSubscribe to not/ind from a characteristic" },
1677  { "unregister-notify", cmd_unregister_notify,
1678  "Unregister a not/ind session"},
1679  { "set-security", cmd_set_security,
1680  "\tSet security level on le connection"},
1681  { "get-security", cmd_get_security,
1682  "\tGet security level on le connection"},
1683  { "set-sign-key", cmd_set_sign_key,
1684  "\tSet signing key for signed write command"},
1685  { "quit", cmd_quit ,"\tQuit"},
1686  { }
1687 };
1688 
1695 static void cmd_help(struct client *cli, char *cmd_str)
1696 {
1697  int i;
1698 
1699  printf("Commands:\n");
1700  for (i = 0; command[i].cmd; i++)
1701  printf("\t%-15s\t%s\n", command[i].cmd, command[i].doc);
1702 }
1703 
1711 static void prompt_read_cb(int fd, uint32_t events, void *user_data)
1712 {
1713  ssize_t read;
1714  size_t len = 0;
1715  char *line = NULL;
1716  char *cmd = NULL, *args;
1717  struct client *cli = user_data;
1718  int i;
1719 
1720  if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) {
1721  mainloop_quit();
1722  return;
1723  }
1724 
1725  if ((read = getline(&line, &len, stdin)) == -1)
1726  return;
1727 
1728  if (read <= 1) {
1729  cmd_help(cli, NULL);
1730  print_prompt();
1731  return;
1732  }
1733 
1734  line[read-1] = '\0';
1735  args = line;
1736 
1737  while ((cmd = strsep(&args, " \t")))
1738  if (*cmd != '\0')
1739  break;
1740 
1741  if (!cmd)
1742  goto failed;
1743 
1744  for (i = 0; command[i].cmd; i++) {
1745  if (strcmp(command[i].cmd, cmd) == 0)
1746  break;
1747  }
1748 
1749  if (command[i].cmd)
1750  command[i].func(cli, args);
1751  else
1752  fprintf(stderr, "Unknown command: %s\n", line);
1753 
1754 failed:
1755  print_prompt();
1756 
1757  free(line);
1758 }
1759 
1766 static void signal_cb(int signum, void *user_data)
1767 {
1768  switch (signum) {
1769  case SIGINT:
1770  case SIGTERM:
1771  mainloop_quit();
1772  break;
1773  default:
1774  break;
1775  }
1776 }
1777 
1787 static int l2cap_le_att_connect(bdaddr_t *src, bdaddr_t *dst, uint8_t dst_type,
1788  int sec)
1789 {
1790  int sock;
1791  struct sockaddr_l2 srcaddr, dstaddr;
1792  struct bt_security btsec;
1793 
1794  if (verbose) {
1795  char srcaddr_str[18], dstaddr_str[18];
1796 
1797  ba2str(src, srcaddr_str);
1798  ba2str(dst, dstaddr_str);
1799 
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);
1803  }
1804 
1805  sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
1806  if (sock < 0) {
1807  perror("Failed to create L2CAP socket");
1808  return -1;
1809  }
1810 
1811  /* Set up source address */
1812  memset(&srcaddr, 0, sizeof(srcaddr));
1813  srcaddr.l2_family = AF_BLUETOOTH;
1814  srcaddr.l2_cid = htobs(ATT_CID);
1815  srcaddr.l2_bdaddr_type = 0;
1816  bacpy(&srcaddr.l2_bdaddr, src);
1817 
1818  if (bind(sock, (struct sockaddr *)&srcaddr, sizeof(srcaddr)) < 0) {
1819  perror("Failed to bind L2CAP socket");
1820  close(sock);
1821  return -1;
1822  }
1823 
1824  /* Set the security level */
1825  memset(&btsec, 0, sizeof(btsec));
1826  btsec.level = sec;
1827  if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &btsec,
1828  sizeof(btsec)) != 0) {
1829  fprintf(stderr, "Failed to set L2CAP security level\n");
1830  close(sock);
1831  return -1;
1832  }
1833 
1834  /* Set up destination address */
1835  memset(&dstaddr, 0, sizeof(dstaddr));
1836  dstaddr.l2_family = AF_BLUETOOTH;
1837  dstaddr.l2_cid = htobs(ATT_CID);
1838  dstaddr.l2_bdaddr_type = dst_type;
1839  bacpy(&dstaddr.l2_bdaddr, dst);
1840 
1841  printf("Connecting to device...");
1842  fflush(stdout);
1843 
1844  if (connect(sock, (struct sockaddr *) &dstaddr, sizeof(dstaddr)) < 0) {
1845  perror(" Failed to connect");
1846  close(sock);
1847  return -1;
1848  }
1849 
1850  printf(" Done\n");
1851 
1852  return sock;
1853 }
1854 
1858 static void usage(void)
1859 {
1860  printf("btgatt-client\n");
1861  printf("Usage:\n\tbtgatt-client [options]\n");
1862 
1863  printf("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|"
1869  "medium|high)\n"
1870  "\t-v, --verbose\t\t\tEnable extra logging\n"
1871  "\t-h, --help\t\t\tDisplay help\n");
1872 
1873  printf("Example:\n"
1874  "btgattclient -v -d C4:BE:84:70:29:04\n");
1875 }
1876 
1877 static struct option main_options[] = {
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' },
1885  { }
1886 };
1887 
1896 int main(int argc, char *argv[])
1897 {
1898  int opt;
1899  int sec = BT_SECURITY_LOW;
1900  uint16_t mtu = 0;
1901  uint8_t dst_type = BDADDR_LE_PUBLIC;
1902  bool dst_addr_given = false;
1903  bdaddr_t src_addr, dst_addr;
1904  int dev_id = -1;
1905  int fd;
1906  sigset_t mask;
1907  struct client *cli;
1908 
1909  while ((opt = getopt_long(argc, argv, "+hvs:m:t:d:i:",
1910  main_options, NULL)) != -1) {
1911  switch (opt) {
1912  case 'h':
1913  usage();
1914  return EXIT_SUCCESS;
1915  case 'v':
1916  verbose = true;
1917  break;
1918  case 's':
1919  if (strcmp(optarg, "low") == 0)
1920  sec = BT_SECURITY_LOW;
1921  else if (strcmp(optarg, "medium") == 0)
1922  sec = BT_SECURITY_MEDIUM;
1923  else if (strcmp(optarg, "high") == 0)
1924  sec = BT_SECURITY_HIGH;
1925  else {
1926  fprintf(stderr, "Invalid security level\n");
1927  return EXIT_FAILURE;
1928  }
1929  break;
1930  case 'm': {
1931  int arg;
1932 
1933  arg = atoi(optarg);
1934  if (arg <= 0) {
1935  fprintf(stderr, "Invalid MTU: %d\n", arg);
1936  return EXIT_FAILURE;
1937  }
1938 
1939  if (arg > UINT16_MAX) {
1940  fprintf(stderr, "MTU too large: %d\n", arg);
1941  return EXIT_FAILURE;
1942  }
1943 
1944  mtu = (uint16_t)arg;
1945  break;
1946  }
1947  case 't':
1948  if (strcmp(optarg, "random") == 0)
1949  dst_type = BDADDR_LE_RANDOM;
1950  else if (strcmp(optarg, "public") == 0)
1951  dst_type = BDADDR_LE_PUBLIC;
1952  else {
1953  fprintf(stderr,
1954  "Allowed types: random, public\n");
1955  return EXIT_FAILURE;
1956  }
1957  break;
1958  case 'd':
1959  if (str2ba(optarg, &dst_addr) < 0) {
1960  fprintf(stderr, "Invalid remote address: %s\n",
1961  optarg);
1962  return EXIT_FAILURE;
1963  }
1964 
1965  dst_addr_given = true;
1966  break;
1967 
1968  case 'i':
1969  dev_id = hci_devid(optarg);
1970  if (dev_id < 0) {
1971  perror("Invalid adapter");
1972  return EXIT_FAILURE;
1973  }
1974 
1975  break;
1976  default:
1977  fprintf(stderr, "Invalid option: %c\n", opt);
1978  return EXIT_FAILURE;
1979  }
1980  }
1981 
1982  if (!argc) {
1983  usage();
1984  return EXIT_SUCCESS;
1985  }
1986 
1987  argc -= optind;
1988  argv += optind;
1989  optind = 0;
1990 
1991  if (argc) {
1992  usage();
1993  return EXIT_SUCCESS;
1994  }
1995 
1996  if (dev_id == -1)
1997  bacpy(&src_addr, BDADDR_ANY);
1998  else if (hci_devba(dev_id, &src_addr) < 0) {
1999  perror("Adapter not available");
2000  return EXIT_FAILURE;
2001  }
2002 
2003  if (!dst_addr_given) {
2004  fprintf(stderr, "Destination address required!\n");
2005  return EXIT_FAILURE;
2006  }
2007 
2008  /* create the mainloop resources */
2009  mainloop_init();
2010 
2011  fd = l2cap_le_att_connect(&src_addr, &dst_addr, dst_type, sec);
2012  if (fd < 0)
2013  return EXIT_FAILURE;
2014 
2015  cli = client_create(fd, mtu);
2016  if (!cli) {
2017  close(fd);
2018  return EXIT_FAILURE;
2019  }
2020 
2021  /* add input event from console */
2022  if (mainloop_add_fd(fileno(stdin),
2023  EPOLLIN | EPOLLRDHUP | EPOLLHUP | EPOLLERR,
2024  prompt_read_cb, cli, NULL) < 0) {
2025  fprintf(stderr, "Failed to initialize console\n");
2026  return EXIT_FAILURE;
2027  }
2028 
2029  sigemptyset(&mask);
2030  sigaddset(&mask, SIGINT);
2031  sigaddset(&mask, SIGTERM);
2032 
2033  /* add handler for process interrupted (SIGINT) or terminated (SIGTERM)*/
2034  mainloop_set_signal(&mask, signal_cb, NULL, NULL);
2035 
2036  print_prompt();
2037 
2038  /* epoll main loop call
2039  *
2040  * any further process is an epoll event processed in mainloop_run
2041  *
2042  */
2043  mainloop_run();
2044 
2045  printf("\n\nShutting down...\n");
2046 
2047  client_destroy(cli);
2048 
2049  return EXIT_SUCCESS;
2050 }
2051 
#define BT_ERROR_OUT_OF_RANGE
Definition: att-types.h:107
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)
Definition: gatt-db.c:1495
command_func_t func
static void cmd_read_value(struct client *cli, char *cmd_str)
Definition: btgattclient.c:757
static struct client * client_create(int fd, uint16_t mtu)
Definition: btgattclient.c:251
static void prompt_read_cb(int fd, uint32_t events, void *user_data)
#define PF_BLUETOOTH
Definition: bluetooth.h:42
#define BT_SECURITY
Definition: bluetooth.h:63
void bt_gatt_client_unref(struct bt_gatt_client *client)
Definition: gatt-client.c:1804
static void unregister_notify_usage(void)
static struct option write_long_value_options[]
Definition: btgattclient.c:997
static void usage(void)
static void client_destroy(struct client *cli)
Definition: btgattclient.c:326
void gatt_db_unref(struct gatt_db *db)
Definition: gatt-db.c:328
static void signal_cb(int signum, void *user_data)
int fd
socket
Definition: btgattclient.c:83
static void print_service(struct gatt_db_attribute *attr, void *user_data)
Definition: btgattclient.c:424
static void read_multiple_usage(void)
Definition: btgattclient.c:629
static void ready_cb(bool success, uint8_t att_ecode, void *user_data)
Definition: btgattclient.c:492
#define BT_ATT_ERROR_PREPARE_QUEUE_FULL
Definition: att-types.h:89
struct bt_gatt_client * gatt
pointer to a bt_gatt_client structure
Definition: btgattclient.c:89
bool bt_gatt_client_set_security(struct bt_gatt_client *client, int level)
Definition: gatt-client.c:3055
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)
Definition: gatt-client.c:2405
bluetooth GATT client structure
Definition: gatt-client.c:64
uint16_t gatt_db_attribute_get_handle(const struct gatt_db_attribute *attrib)
Definition: gatt-db.c:1409
bool bt_gatt_client_is_ready(struct bt_gatt_client *client)
Definition: gatt-client.c:1815
int mainloop_run(void)
Definition: mainloop.c:174
#define AF_BLUETOOTH
Definition: bluetooth.h:41
bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16], bt_att_counter_func_t func, void *user_data)
Definition: att.c:1506
const bt_uuid_t * gatt_db_attribute_get_type(const struct gatt_db_attribute *attrib)
Definition: gatt-db.c:1400
struct gatt_db * db
pointer to a gatt_db structure
Definition: btgattclient.c:87
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)
Definition: gatt-client.c:3018
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
Definition: uuid.c:285
#define BT_ERROR_ALREADY_IN_PROGRESS
Definition: att-types.h:106
static void print_uuid(const bt_uuid_t *uuid)
Definition: btgattclient.c:338
static void cmd_read_long_value(struct client *cli, char *cmd_str)
Definition: btgattclient.c:799
static void print_services(struct client *cli)
Definition: btgattclient.c:451
void mainloop_quit(void)
Definition: mainloop.c:116
#define BT_ATT_ERROR_INVALID_OFFSET
Definition: att-types.h:87
bool gatt_db_attribute_get_service_uuid(const struct gatt_db_attribute *attrib, bt_uuid_t *uuid)
Definition: gatt-db.c:1417
static void read_cb(bool success, uint8_t att_ecode, const uint8_t *value, uint16_t length, void *user_data)
Definition: btgattclient.c:725
#define BDADDR_ANY
Definition: bluetooth.h:309
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)
Definition: gatt-db.c:1237
static void print_incl(struct gatt_db_attribute *attr, void *user_data)
Definition: btgattclient.c:355
#define COLOR_MAGENTA
Definition: btgattclient.c:72
int hci_devba(int dev_id, bdaddr_t *bdaddr)
Definition: hci.c:1182
uint8_t l2_bdaddr_type
Definition: l2cap.h:46
static void services_usage(void)
Definition: btgattclient.c:531
void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
Definition: uuid.c:85
int hci_devid(const char *str)
Definition: hci.c:1130
static void service_changed_cb(uint16_t start_handle, uint16_t end_handle, void *user_data)
Definition: btgattclient.c:515
static void service_removed_cb(struct gatt_db_attribute *attr, void *user_data)
Definition: btgattclient.c:239
void gatt_db_service_foreach_char(struct gatt_db_attribute *attrib, gatt_db_attribute_cb_t func, void *user_data)
Definition: gatt-db.c:1284
struct bt_att * att
pointer to a bt_att structure
Definition: btgattclient.c:85
#define BT_ATT_ERROR_AUTHORIZATION
Definition: att-types.h:88
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)
Definition: gatt-client.c:1838
int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback, void *user_data, mainloop_destroy_func destroy)
Definition: mainloop.c:457
static void cmd_services(struct client *cli, char *cmd_str)
Definition: btgattclient.c:575
static void read_long_value_usage(void)
Definition: btgattclient.c:788
int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback, void *user_data, mainloop_destroy_func destroy)
Definition: mainloop.c:252
static bool convert_sign_key(char *optarg, uint8_t key[16])
static void print_chrc(struct gatt_db_attribute *attr, void *user_data)
Definition: btgattclient.c:397
void mainloop_init(void)
Definition: mainloop.c:101
static void notify_cb(uint16_t value_handle, const uint8_t *value, uint16_t length, void *user_data)
#define COLOR_BLUE
Definition: btgattclient.c:71
#define BT_SECURITY_LOW
Definition: bluetooth.h:69
struct gatt_db * gatt_db_new(void)
Definition: gatt-db.c:218
static struct @3 command[]
static bool verbose
Definition: btgattclient.c:76
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)
Definition: gatt-db.c:605
void * user_data
Definition: gatt-db.c:104
#define htobs(d)
Definition: bluetooth.h:140
#define BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN
Definition: att-types.h:93
static void write_value_usage(void)
Definition: btgattclient.c:838
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)
Definition: gatt-db.c:1330
static void read_value_usage(void)
Definition: btgattclient.c:711
static void bacpy(bdaddr_t *dst, const bdaddr_t *src)
Definition: bluetooth.h:318
#define COLOR_BOLDWHITE
Definition: btgattclient.c:74
void(* command_func_t)(struct client *cli, char *cmd_str)
#define BT_ATT_ERROR_UNLIKELY
Definition: att-types.h:94
bool bt_att_set_debug(struct bt_att *att, bt_att_debug_func_t callback, void *user_data, bt_att_destroy_func_t destroy)
Definition: att.c:1095
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)
Definition: gatt-db.c:1465
static const char * ecode_to_string(uint8_t ecode)
Definition: btgattclient.c:109
static void set_sign_key_usage(void)
unsigned short l2_cid
Definition: l2cap.h:45
static void print_desc(struct gatt_db_attribute *attr, void *user_data)
Definition: btgattclient.c:383
struct bt_gatt_client * bt_gatt_client_new(struct gatt_db *db, struct bt_att *att, uint16_t mtu)
Definition: gatt-client.c:1733
#define BDADDR_LE_PUBLIC
Definition: bluetooth.h:306
static void register_notify_cb(uint16_t att_ecode, void *user_data)
static void att_disconnect_cb(int err, void *user_data)
Definition: btgattclient.c:163
#define BDADDR_LE_RANDOM
Definition: bluetooth.h:307
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)
Definition: gatt-client.c:1856
static void cmd_set_sign_key(struct client *cli, char *cmd_str)
#define COLOR_RED
Definition: btgattclient.c:68
#define BT_ATT_ERROR_ATTRIBUTE_NOT_LONG
Definition: att-types.h:91
struct bt_att * bt_att_new(int fd, bool ext_signed)
Definition: att.c:991
static struct option write_value_options[]
Definition: btgattclient.c:848
#define BT_ERROR_CCC_IMPROPERLY_CONFIGURED
Definition: att-types.h:105
static void print_services_by_uuid(struct client *cli, const bt_uuid_t *uuid)
Definition: btgattclient.c:464
void gatt_db_foreach_service(struct gatt_db *db, const bt_uuid_t *uuid, gatt_db_attribute_cb_t func, void *user_data)
Definition: gatt-db.c:1200
static void cmd_write_prepare(struct client *cli, char *cmd_str)
uint16_t handle
Definition: gatt-db.c:96
bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client, unsigned int id)
Definition: gatt-client.c:3035
bool bt_att_set_close_on_unref(struct bt_att *att, bool do_close)
Definition: att.c:1079
bool gatt_db_attribute_get_incl_data(const struct gatt_db_attribute *attrib, uint16_t *handle, uint16_t *start_handle, uint16_t *end_handle)
Definition: gatt-db.c:1532
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)
Definition: gatt-client.c:2122
static void gatt_debug_cb(const char *str, void *user_data)
Definition: btgattclient.c:190
bdaddr_t l2_bdaddr
Definition: l2cap.h:44
static void cmd_set_security(struct client *cli, char *cmd_str)
#define BT_ATT_ERROR_UNSUPPORTED_GROUP_TYPE
Definition: att-types.h:96
#define COLOR_OFF
Definition: btgattclient.c:67
#define BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND
Definition: att-types.h:90
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)
Definition: gatt-client.c:2670
static void cmd_unregister_notify(struct client *cli, char *cmd_str)
static void cmd_write_long_value(struct client *cli, char *cmd_str)
#define ATT_CID
Definition: btgattclient.c:62
#define COLOR_YELLOW
Definition: btgattclient.c:70
bool gatt_db_attribute_get_service_handles(const struct gatt_db_attribute *attrib, uint16_t *start_handle, uint16_t *end_handle)
Definition: gatt-db.c:1448
char * doc
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)
Definition: gatt-client.c:1820
static void cmd_write_execute(struct client *cli, char *cmd_str)
#define BT_ATT_ERROR_AUTHENTICATION
Definition: att-types.h:85
bt_uuid_t uuid
Definition: gatt-db.c:97
unsigned int reliable_session_id
session id
Definition: btgattclient.c:91
static int l2cap_le_att_connect(bdaddr_t *src, bdaddr_t *dst, uint8_t dst_type, int sec)
#define PRLOG(...)
Definition: btgattclient.c:64
char * cmd
int bt_gatt_client_get_security(struct bt_gatt_client *client)
Definition: gatt-client.c:3063
#define BT_SECURITY_MEDIUM
Definition: bluetooth.h:70
static void write_cb(bool success, uint8_t att_ecode, void *user_data)
Definition: btgattclient.c:861
#define COLOR_BOLDGRAY
Definition: btgattclient.c:73
#define BT_ATT_ERROR_INVALID_HANDLE
Definition: att-types.h:81
static struct option main_options[]
static void cmd_get_security(struct client *cli, char *cmd_str)
Definition: att.c:64
static void att_debug_cb(const char *str, void *user_data)
Definition: btgattclient.c:177
static void print_services_by_handle(struct client *cli, uint16_t handle)
Definition: btgattclient.c:477
void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib, gatt_db_attribute_cb_t func, void *user_data)
Definition: gatt-db.c:1291
static void cmd_register_notify(struct client *cli, char *cmd_str)
int str2ba(const char *str, bdaddr_t *ba)
Definition: bluetooth.c:92
static void cmd_write_value(struct client *cli, char *cmd_str)
Definition: btgattclient.c:877
#define BT_ATT_ERROR_INSUFFICIENT_RESOURCES
Definition: att-types.h:97
struct gatt_db_attribute * gatt_db_get_attribute(struct gatt_db *db, uint16_t handle)
Definition: gatt-db.c:1349
static void register_notify_usage(void)
static void write_prepare_usage(void)
#define BTPROTO_L2CAP
Definition: bluetooth.h:45
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)
Definition: gatt-client.c:2966
static void service_added_cb(struct gatt_db_attribute *attr, void *user_data)
Definition: btgattclient.c:228
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)
Definition: gatt-client.c:2328
static void write_long_value_usage(void)
Definition: btgattclient.c:987
#define SOL_BLUETOOTH
Definition: bluetooth.h:60
static void print_prompt(void)
Definition: btgattclient.c:97
#define BT_SECURITY_HIGH
Definition: bluetooth.h:71
static void cmd_help(struct client *cli, char *cmd_str)
static bool parse_args(char *str, int expected_argc, char **argv, int *argc)
Definition: btgattclient.c:550
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)
Definition: gatt-client.c:2846
#define BT_ATT_ERROR_INVALID_PDU
Definition: att-types.h:84
int ba2str(const bdaddr_t *ba, char *str)
Definition: bluetooth.c:86
uint8_t level
Definition: bluetooth.h:65
static void log_service_event(struct gatt_db_attribute *attr, const char *str)
Definition: btgattclient.c:207
#define BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE
Definition: att-types.h:92
#define COLOR_GREEN
Definition: btgattclient.c:69
#define BT_ATT_ERROR_READ_NOT_PERMITTED
Definition: att-types.h:82
sa_family_t l2_family
Definition: l2cap.h:42
#define BT_ATT_ERROR_WRITE_NOT_PERMITTED
Definition: att-types.h:83
#define new0(t, n)
Definition: util.h:82
#define BT_ATT_ERROR_REQUEST_NOT_SUPPORTED
Definition: att-types.h:86
static void read_multiple_cb(bool success, uint8_t att_ecode, const uint8_t *value, uint16_t length, void *user_data)
Definition: btgattclient.c:643
struct gatt_db_service * service
Definition: gatt-db.c:95
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)
Definition: gatt-client.c:2279
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)
Definition: att.c:1158
#define MAX_LEN_UUID_STR
Definition: uuid.h:165
void bt_att_unref(struct bt_att *att)
Definition: att.c:1065
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)
Definition: btgattclient.c:668
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)
Definition: gatt-client.c:2050
static void write_execute_usage(void)
int main(int argc, char *argv[])
#define BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION
Definition: att-types.h:95
bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id)
Definition: gatt-client.c:1959
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)
Definition: uuid.c:148