gatttool.c revision d3a5c568829a67da1d31625531bf161d3dc9435e
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2010 Nokia Corporation 6 * Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include <config.h> 27#endif 28 29#include <errno.h> 30#include <glib.h> 31#include <stdlib.h> 32#include <unistd.h> 33 34#include <bluetooth/bluetooth.h> 35#include <bluetooth/hci.h> 36#include <bluetooth/hci_lib.h> 37#include <bluetooth/sdp.h> 38#include <bluetooth/sdp_lib.h> 39 40#include "att.h" 41#include "btio.h" 42#include "gattrib.h" 43#include "glib-helper.h" 44#include "gatt.h" 45#include "gatttool.h" 46 47static gchar *opt_src = NULL; 48static gchar *opt_dst = NULL; 49static gchar *opt_value = NULL; 50static gchar *opt_sec_level = NULL; 51static uuid_t *opt_uuid = NULL; 52static int opt_start = 0x0001; 53static int opt_end = 0xffff; 54static int opt_handle = -1; 55static int opt_mtu = 0; 56static int opt_psm = 0; 57static gboolean opt_primary = FALSE; 58static gboolean opt_characteristics = FALSE; 59static gboolean opt_char_read = FALSE; 60static gboolean opt_listen = FALSE; 61static gboolean opt_char_desc = FALSE; 62static gboolean opt_char_write = FALSE; 63static gboolean opt_char_write_req = FALSE; 64static gboolean opt_interactive = FALSE; 65static GMainLoop *event_loop; 66static gboolean got_error = FALSE; 67 68struct characteristic_data { 69 GAttrib *attrib; 70 uint16_t start; 71 uint16_t end; 72}; 73 74static void connect_cb(GIOChannel *io, GError *err, gpointer user_data) 75{ 76 if (err) { 77 g_printerr("%s\n", err->message); 78 got_error = TRUE; 79 g_main_loop_quit(event_loop); 80 } 81} 82 83static void primary_all_cb(GSList *services, guint8 status, gpointer user_data) 84{ 85 GSList *l; 86 87 if (status) { 88 g_printerr("Discover all primary services failed: %s\n", 89 att_ecode2str(status)); 90 goto done; 91 } 92 93 for (l = services; l; l = l->next) { 94 struct att_primary *prim = l->data; 95 g_print("attr handle = 0x%04x, end grp handle = 0x%04x " 96 "uuid: %s\n", prim->start, prim->end, prim->uuid); 97 } 98 99done: 100 g_main_loop_quit(event_loop); 101} 102 103static void primary_by_uuid_cb(GSList *ranges, guint8 status, 104 gpointer user_data) 105{ 106 GSList *l; 107 108 if (status != 0) { 109 g_printerr("Discover primary services by UUID failed: %s\n", 110 att_ecode2str(status)); 111 goto done; 112 } 113 114 for (l = ranges; l; l = l->next) { 115 struct att_range *range = l->data; 116 g_print("Starting handle: %04x Ending handle: %04x\n", 117 range->start, range->end); 118 } 119 120done: 121 g_main_loop_quit(event_loop); 122} 123 124static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data) 125{ 126 GAttrib *attrib = user_data; 127 uint8_t opdu[ATT_MAX_MTU]; 128 uint16_t handle, i, olen = 0; 129 130 handle = att_get_u16(&pdu[1]); 131 132 switch (pdu[0]) { 133 case ATT_OP_HANDLE_NOTIFY: 134 g_print("Notification handle = 0x%04x value: ", handle); 135 break; 136 case ATT_OP_HANDLE_IND: 137 g_print("Indication handle = 0x%04x value: ", handle); 138 break; 139 default: 140 g_print("Invalid opcode\n"); 141 return; 142 } 143 144 for (i = 3; i < len; i++) 145 g_print("%02x ", pdu[i]); 146 147 g_print("\n"); 148 149 if (pdu[0] == ATT_OP_HANDLE_NOTIFY) 150 return; 151 152 olen = enc_confirmation(opdu, sizeof(opdu)); 153 154 if (olen > 0) 155 g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL); 156} 157 158static gboolean listen_start(gpointer user_data) 159{ 160 GAttrib *attrib = user_data; 161 162 g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, events_handler, 163 attrib, NULL); 164 g_attrib_register(attrib, ATT_OP_HANDLE_IND, events_handler, 165 attrib, NULL); 166 167 return FALSE; 168} 169 170static gboolean primary(gpointer user_data) 171{ 172 GAttrib *attrib = user_data; 173 174 if (opt_uuid) 175 gatt_discover_primary(attrib, opt_uuid, primary_by_uuid_cb, 176 NULL); 177 else 178 gatt_discover_primary(attrib, NULL, primary_all_cb, NULL); 179 180 return FALSE; 181} 182 183static void char_discovered_cb(GSList *characteristics, guint8 status, 184 gpointer user_data) 185{ 186 GSList *l; 187 188 if (status) { 189 g_printerr("Discover all characteristics failed: %s\n", 190 att_ecode2str(status)); 191 goto done; 192 } 193 194 for (l = characteristics; l; l = l->next) { 195 struct att_char *chars = l->data; 196 197 g_print("handle = 0x%04x, char properties = 0x%02x, char value " 198 "handle = 0x%04x, uuid = %s\n", chars->handle, 199 chars->properties, chars->value_handle, chars->uuid); 200 } 201 202done: 203 g_main_loop_quit(event_loop); 204} 205 206static gboolean characteristics(gpointer user_data) 207{ 208 GAttrib *attrib = user_data; 209 210 gatt_discover_char(attrib, opt_start, opt_end, char_discovered_cb, NULL); 211 212 return FALSE; 213} 214 215static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen, 216 gpointer user_data) 217{ 218 uint8_t value[ATT_MAX_MTU]; 219 int i, vlen; 220 221 if (status != 0) { 222 g_printerr("Characteristic value/descriptor read failed: %s\n", 223 att_ecode2str(status)); 224 goto done; 225 } 226 if (!dec_read_resp(pdu, plen, value, &vlen)) { 227 g_printerr("Protocol error\n"); 228 goto done; 229 } 230 g_print("Characteristic value/descriptor: "); 231 for (i = 0; i < vlen; i++) 232 g_print("%02x ", value[i]); 233 g_print("\n"); 234 235done: 236 if (opt_listen == FALSE) 237 g_main_loop_quit(event_loop); 238} 239 240static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu, 241 guint16 plen, gpointer user_data) 242{ 243 struct characteristic_data *char_data = user_data; 244 struct att_data_list *list; 245 int i; 246 247 if (status == ATT_ECODE_ATTR_NOT_FOUND && 248 char_data->start != opt_start) 249 goto done; 250 251 if (status != 0) { 252 g_printerr("Read characteristics by UUID failed: %s\n", 253 att_ecode2str(status)); 254 goto done; 255 } 256 257 list = dec_read_by_type_resp(pdu, plen); 258 if (list == NULL) 259 goto done; 260 261 for (i = 0; i < list->num; i++) { 262 uint8_t *value = list->data[i]; 263 int j; 264 265 char_data->start = att_get_u16(value) + 1; 266 267 g_print("handle: 0x%04x \t value: ", att_get_u16(value)); 268 value += 2; 269 for (j = 0; j < list->len - 2; j++, value++) 270 g_print("%02x ", *value); 271 g_print("\n"); 272 } 273 274 att_data_list_free(list); 275 276 gatt_read_char_by_uuid(char_data->attrib, char_data->start, 277 char_data->end, opt_uuid, 278 char_read_by_uuid_cb, 279 char_data); 280 281 return; 282done: 283 g_free(char_data); 284 g_main_loop_quit(event_loop); 285} 286 287static gboolean characteristics_read(gpointer user_data) 288{ 289 GAttrib *attrib = user_data; 290 291 if (opt_uuid != NULL) { 292 struct characteristic_data *char_data; 293 294 char_data = g_new(struct characteristic_data, 1); 295 char_data->attrib = attrib; 296 char_data->start = opt_start; 297 char_data->end = opt_end; 298 299 gatt_read_char_by_uuid(attrib, opt_start, opt_end, opt_uuid, 300 char_read_by_uuid_cb, char_data); 301 302 return FALSE; 303 } 304 305 if (opt_handle <= 0) { 306 g_printerr("A valid handle is required\n"); 307 g_main_loop_quit(event_loop); 308 return FALSE; 309 } 310 311 gatt_read_char(attrib, opt_handle, char_read_cb, attrib); 312 313 return FALSE; 314} 315 316static void mainloop_quit(gpointer user_data) 317{ 318 uint8_t *value = user_data; 319 320 g_free(value); 321 g_main_loop_quit(event_loop); 322} 323 324static gboolean characteristics_write(gpointer user_data) 325{ 326 GAttrib *attrib = user_data; 327 uint8_t *value; 328 size_t len; 329 330 if (opt_handle <= 0) { 331 g_printerr("A valid handle is required\n"); 332 goto error; 333 } 334 335 if (opt_value == NULL || opt_value[0] == '\0') { 336 g_printerr("A value is required\n"); 337 goto error; 338 } 339 340 len = gatt_attr_data_from_string(opt_value, &value); 341 if (len == 0) { 342 g_printerr("Invalid value\n"); 343 goto error; 344 } 345 346 gatt_write_cmd(attrib, opt_handle, value, len, mainloop_quit, value); 347 348 return FALSE; 349 350error: 351 g_main_loop_quit(event_loop); 352 return FALSE; 353} 354 355static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen, 356 gpointer user_data) 357{ 358 if (status != 0) { 359 g_printerr("Characteristic Write Request failed: " 360 "%s\n", att_ecode2str(status)); 361 goto done; 362 } 363 364 if (!dec_write_resp(pdu, plen)) { 365 g_printerr("Protocol error\n"); 366 goto done; 367 } 368 369 g_print("Characteristic value was written sucessfully\n"); 370 371done: 372 if (opt_listen == FALSE) 373 g_main_loop_quit(event_loop); 374} 375 376static gboolean characteristics_write_req(gpointer user_data) 377{ 378 GAttrib *attrib = user_data; 379 uint8_t *value; 380 size_t len; 381 382 if (opt_handle <= 0) { 383 g_printerr("A valid handle is required\n"); 384 goto error; 385 } 386 387 if (opt_value == NULL || opt_value[0] == '\0') { 388 g_printerr("A value is required\n"); 389 goto error; 390 } 391 392 len = gatt_attr_data_from_string(opt_value, &value); 393 if (len == 0) { 394 g_printerr("Invalid value\n"); 395 goto error; 396 } 397 398 gatt_write_char(attrib, opt_handle, value, len, char_write_req_cb, 399 NULL); 400 401 return FALSE; 402 403error: 404 g_main_loop_quit(event_loop); 405 return FALSE; 406} 407 408static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen, 409 gpointer user_data) 410{ 411 struct att_data_list *list; 412 guint8 format; 413 int i; 414 415 if (status != 0) { 416 g_printerr("Discover all characteristic descriptors failed: " 417 "%s\n", att_ecode2str(status)); 418 goto done; 419 } 420 421 list = dec_find_info_resp(pdu, plen, &format); 422 if (list == NULL) 423 goto done; 424 425 for (i = 0; i < list->num; i++) { 426 char uuidstr[MAX_LEN_UUID_STR]; 427 uint16_t handle; 428 uint8_t *value; 429 uuid_t uuid; 430 431 value = list->data[i]; 432 handle = att_get_u16(value); 433 434 if (format == 0x01) 435 sdp_uuid16_create(&uuid, att_get_u16(&value[2])); 436 else 437 sdp_uuid128_create(&uuid, &value[2]); 438 439 sdp_uuid2strn(&uuid, uuidstr, MAX_LEN_UUID_STR); 440 g_print("handle = 0x%04x, uuid = %s\n", handle, uuidstr); 441 } 442 443 att_data_list_free(list); 444 445done: 446 if (opt_listen == FALSE) 447 g_main_loop_quit(event_loop); 448} 449 450static gboolean characteristics_desc(gpointer user_data) 451{ 452 GAttrib *attrib = user_data; 453 454 gatt_find_info(attrib, opt_start, opt_end, char_desc_cb, NULL); 455 456 return FALSE; 457} 458 459static gboolean parse_uuid(const char *key, const char *value, 460 gpointer user_data, GError **error) 461{ 462 if (!value) 463 return FALSE; 464 465 opt_uuid = g_try_malloc(sizeof(uuid_t)); 466 if (opt_uuid == NULL) 467 return FALSE; 468 469 if (bt_string2uuid(opt_uuid, value) < 0) 470 return FALSE; 471 472 return TRUE; 473} 474 475static GOptionEntry primary_char_options[] = { 476 { "start", 's' , 0, G_OPTION_ARG_INT, &opt_start, 477 "Starting handle(optional)", "0x0001" }, 478 { "end", 'e' , 0, G_OPTION_ARG_INT, &opt_end, 479 "Ending handle(optional)", "0xffff" }, 480 { "uuid", 'u', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, 481 parse_uuid, "UUID16 or UUID128(optional)", "0x1801"}, 482 { NULL }, 483}; 484 485static GOptionEntry char_rw_options[] = { 486 { "handle", 'a' , 0, G_OPTION_ARG_INT, &opt_handle, 487 "Read/Write characteristic by handle(required)", "0x0001" }, 488 { "value", 'n' , 0, G_OPTION_ARG_STRING, &opt_value, 489 "Write characteristic value (required for write operation)", 490 "0x0001" }, 491 {NULL}, 492}; 493 494static GOptionEntry gatt_options[] = { 495 { "primary", 0, 0, G_OPTION_ARG_NONE, &opt_primary, 496 "Primary Service Discovery", NULL }, 497 { "characteristics", 0, 0, G_OPTION_ARG_NONE, &opt_characteristics, 498 "Characteristics Discovery", NULL }, 499 { "char-read", 0, 0, G_OPTION_ARG_NONE, &opt_char_read, 500 "Characteristics Value/Descriptor Read", NULL }, 501 { "char-write", 0, 0, G_OPTION_ARG_NONE, &opt_char_write, 502 "Characteristics Value Write Without Response (Write Command)", 503 NULL }, 504 { "char-write-req", 0, 0, G_OPTION_ARG_NONE, &opt_char_write_req, 505 "Characteristics Value Write (Write Request)", NULL }, 506 { "char-desc", 0, 0, G_OPTION_ARG_NONE, &opt_char_desc, 507 "Characteristics Descriptor Discovery", NULL }, 508 { "listen", 0, 0, G_OPTION_ARG_NONE, &opt_listen, 509 "Listen for notifications and indications", NULL }, 510 { "interactive", 'I', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, 511 &opt_interactive, "Use interactive mode", NULL }, 512 { NULL }, 513}; 514 515static GOptionEntry options[] = { 516 { "adapter", 'i', 0, G_OPTION_ARG_STRING, &opt_src, 517 "Specify local adapter interface", "hciX" }, 518 { "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst, 519 "Specify remote Bluetooth address", "MAC" }, 520 { "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu, 521 "Specify the MTU size", "MTU" }, 522 { "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm, 523 "Specify the PSM for GATT/ATT over BR/EDR", "PSM" }, 524 { "sec-level", 'l', 0, G_OPTION_ARG_STRING, &opt_sec_level, 525 "Set security level. Default: low", "[low | medium | high]"}, 526 { NULL }, 527}; 528 529int main(int argc, char *argv[]) 530{ 531 GOptionContext *context; 532 GOptionGroup *gatt_group, *params_group, *char_rw_group; 533 GError *gerr = NULL; 534 GAttrib *attrib; 535 GIOChannel *chan; 536 GSourceFunc callback; 537 538 opt_sec_level = strdup("low"); 539 540 context = g_option_context_new(NULL); 541 g_option_context_add_main_entries(context, options, NULL); 542 543 /* GATT commands */ 544 gatt_group = g_option_group_new("gatt", "GATT commands", 545 "Show all GATT commands", NULL, NULL); 546 g_option_context_add_group(context, gatt_group); 547 g_option_group_add_entries(gatt_group, gatt_options); 548 549 /* Primary Services and Characteristics arguments */ 550 params_group = g_option_group_new("params", 551 "Primary Services/Characteristics arguments", 552 "Show all Primary Services/Characteristics arguments", 553 NULL, NULL); 554 g_option_context_add_group(context, params_group); 555 g_option_group_add_entries(params_group, primary_char_options); 556 557 /* Characteristics value/descriptor read/write arguments */ 558 char_rw_group = g_option_group_new("char-read-write", 559 "Characteristics Value/Descriptor Read/Write arguments", 560 "Show all Characteristics Value/Descriptor Read/Write " 561 "arguments", 562 NULL, NULL); 563 g_option_context_add_group(context, char_rw_group); 564 g_option_group_add_entries(char_rw_group, char_rw_options); 565 566 if (g_option_context_parse(context, &argc, &argv, &gerr) == FALSE) { 567 g_printerr("%s\n", gerr->message); 568 g_error_free(gerr); 569 } 570 571 if (opt_interactive) { 572 interactive(opt_dst, opt_psm); 573 goto done; 574 } 575 576 if (opt_primary) 577 callback = primary; 578 else if (opt_characteristics) 579 callback = characteristics; 580 else if (opt_char_read) 581 callback = characteristics_read; 582 else if (opt_char_write) 583 callback = characteristics_write; 584 else if (opt_char_write_req) 585 callback = characteristics_write_req; 586 else if (opt_char_desc) 587 callback = characteristics_desc; 588 else { 589 gchar *help = g_option_context_get_help(context, TRUE, NULL); 590 g_print("%s\n", help); 591 g_free(help); 592 got_error = TRUE; 593 goto done; 594 } 595 596 chan = gatt_connect(opt_src, opt_dst, opt_sec_level, 597 opt_psm, opt_mtu, connect_cb); 598 if (chan == NULL) { 599 got_error = TRUE; 600 goto done; 601 } 602 603 attrib = g_attrib_new(chan); 604 g_io_channel_unref(chan); 605 606 event_loop = g_main_loop_new(NULL, FALSE); 607 608 if (opt_listen) 609 g_idle_add(listen_start, attrib); 610 611 g_idle_add(callback, attrib); 612 613 g_main_loop_run(event_loop); 614 615 g_attrib_unregister_all(attrib); 616 617 g_main_loop_unref(event_loop); 618 619 g_attrib_unref(attrib); 620 621done: 622 g_option_context_free(context); 623 g_free(opt_src); 624 g_free(opt_dst); 625 g_free(opt_uuid); 626 g_free(opt_sec_level); 627 628 if (got_error) 629 exit(EXIT_FAILURE); 630 else 631 exit(EXIT_SUCCESS); 632} 633