gatttool.c revision da394a7e17aa455f3b71c8b1e5402541fc141425
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/l2cap.h> 36#include <bluetooth/hci.h> 37#include <bluetooth/hci_lib.h> 38#include <bluetooth/sdp.h> 39#include <bluetooth/sdp_lib.h> 40 41#include "att.h" 42#include "gattrib.h" 43#include "gatt.h" 44 45#define GATT_PSM 27 46 47static gchar *opt_src = NULL; 48static gchar *opt_dst = NULL; 49static int opt_start = 0x0001; 50static int opt_end = 0xffff; 51static int opt_handle = 0x0001; 52static gboolean opt_primary = FALSE; 53static gboolean opt_characteristics = FALSE; 54static gboolean opt_char_read = FALSE; 55static gboolean opt_listen = FALSE; 56static guint listen_watch = 0; 57static gboolean opt_char_desc = FALSE; 58static GMainLoop *event_loop; 59 60struct characteristic_data { 61 GAttrib *attrib; 62 uint16_t start; 63 uint16_t end; 64}; 65 66static int l2cap_connect(void) 67{ 68 struct sockaddr_l2 addr; 69 bdaddr_t sba, dba; 70 int err, sk; 71 72 /* Remote device */ 73 if (opt_dst == NULL) { 74 g_printerr("Remote Bluetooth address required\n"); 75 return -EINVAL; 76 } 77 78 str2ba(opt_dst, &dba); 79 80 /* Local adapter */ 81 if (opt_src != NULL) { 82 if (!strncmp(opt_src, "hci", 3)) 83 hci_devba(atoi(opt_src + 3), &sba); 84 else 85 str2ba(opt_src, &sba); 86 } else 87 bacpy(&sba, BDADDR_ANY); 88 89 sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); 90 if (sk < 0) { 91 err = errno; 92 g_printerr("L2CAP socket create failed: %s(%d)\n", 93 strerror(err), err); 94 return -err; 95 } 96 97 memset(&addr, 0, sizeof(addr)); 98 addr.l2_family = AF_BLUETOOTH; 99 bacpy(&addr.l2_bdaddr, &sba); 100 101 if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 102 err = errno; 103 g_printerr("L2CAP socket bind failed: %s(%d)\n", 104 strerror(err), err); 105 close(sk); 106 return -err; 107 } 108 109 memset(&addr, 0, sizeof(addr)); 110 addr.l2_family = AF_BLUETOOTH; 111 bacpy(&addr.l2_bdaddr, &dba); 112 addr.l2_psm = htobs(GATT_PSM); 113 114 err = connect(sk, (struct sockaddr *) &addr, sizeof(addr)); 115 if (err < 0) { 116 err = errno; 117 g_printerr("L2CAP socket connect failed: %s(%d)\n", 118 strerror(err), err); 119 close(sk); 120 return -err; 121 } 122 123 return sk; 124} 125 126static GIOChannel *do_connect(void) 127{ 128 GIOChannel *chan; 129 int sk; 130 131 sk = l2cap_connect(); 132 if (sk < 0) 133 return NULL; 134 135 chan = g_io_channel_unix_new(sk); 136 g_io_channel_set_flags(chan, G_IO_FLAG_NONBLOCK, NULL); 137 g_io_channel_set_close_on_unref(chan, TRUE); 138 139 return chan; 140} 141 142static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen, 143 gpointer user_data) 144{ 145 GAttrib *attrib = user_data; 146 struct att_data_list *list; 147 unsigned int i; 148 uint16_t end; 149 150 if (status == ATT_ECODE_ATTR_NOT_FOUND) 151 goto done; 152 153 if (status != 0) { 154 g_printerr("Discover all primary services failed: %s\n", 155 att_ecode2str(status)); 156 goto done; 157 } 158 159 list = dec_read_by_grp_resp(pdu, plen); 160 if (list == NULL) 161 goto done; 162 163 for (i = 0, end = 0; i < list->num; i++) { 164 char uuidstr[MAX_LEN_UUID_STR]; 165 uint8_t *value = list->data[i]; 166 uint8_t length; 167 uint16_t start; 168 uuid_t uuid; 169 170 /* Each element contains: attribute handle, end group handle 171 * and attribute value */ 172 length = list->len - 2 * sizeof(uint16_t); 173 start = att_get_u16((uint16_t *) value); 174 end = att_get_u16((uint16_t *) &value[2]); 175 176 g_print("attr handle = 0x%04x, end grp handle = 0x%04x, ", 177 start, end); 178 if (length == 2) 179 sdp_uuid16_create(&uuid, att_get_u16((uint16_t *) 180 &value[4])); 181 else 182 sdp_uuid128_create(&uuid, value + 4); 183 184 sdp_uuid2strn(&uuid, uuidstr, MAX_LEN_UUID_STR); 185 g_print("attr value (UUID) = %s\n", uuidstr); 186 } 187 188 att_data_list_free(list); 189 190 /* 191 * Discover all primary services sub-procedure shall send another 192 * Read by Group Type Request until Error Response is received and 193 * the Error Code is set to Attribute Not Found. 194 */ 195 gatt_discover_primary(attrib, end + 1, opt_end, primary_cb, attrib); 196 197 return; 198 199done: 200 if (opt_listen == FALSE) 201 g_main_loop_quit(event_loop); 202} 203 204static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data) 205{ 206 uint16_t handle, i; 207 208 handle = att_get_u16((uint16_t *) &pdu[1]); 209 210 switch (pdu[0]) { 211 case ATT_OP_HANDLE_NOTIFY: 212 g_print("attr handle = 0x%04x value: ", handle); 213 for (i = 3; i < len; i++) 214 g_print("%02x ", pdu[i]); 215 216 g_print("\n"); 217 break; 218 case ATT_OP_HANDLE_IND: 219 break; 220 } 221} 222 223static gboolean listen_start(gpointer user_data) 224{ 225 GAttrib *attrib = user_data; 226 uint8_t events = ATT_OP_HANDLE_NOTIFY; 227 228 listen_watch = g_attrib_register(attrib, events, events_handler, 229 NULL, NULL); 230 231 return FALSE; 232} 233 234static gboolean primary(gpointer user_data) 235{ 236 GAttrib *attrib = user_data; 237 238 gatt_discover_primary(attrib, opt_start, opt_end, primary_cb, attrib); 239 240 return FALSE; 241} 242 243static void char_discovered_cb(guint8 status, const guint8 *pdu, guint16 plen, 244 gpointer user_data) 245{ 246 struct characteristic_data *char_data = user_data; 247 struct att_data_list *list; 248 uint16_t last = char_data->start; 249 int i; 250 251 if (status == ATT_ECODE_ATTR_NOT_FOUND) 252 goto done; 253 254 if (status != 0) { 255 g_printerr("Discover all characteristics failed: %s\n", 256 att_ecode2str(status)); 257 goto done; 258 } 259 260 list = dec_read_by_type_resp(pdu, plen); 261 if (list == NULL) 262 return; 263 264 for (i = 0; i < list->num; i++) { 265 uint8_t *value = list->data[i]; 266 char uuidstr[MAX_LEN_UUID_STR]; 267 uuid_t uuid; 268 269 last = att_get_u16((uint16_t *) value); 270 271 g_print("handle = 0x%04x, char properties = 0x%02x, " 272 "char value handle = 0x%04x, ", last, value[2], 273 att_get_u16((uint16_t *) &value[3])); 274 275 if (list->len == 7) 276 sdp_uuid16_create(&uuid, att_get_u16((uint16_t *) 277 &value[5])); 278 else 279 sdp_uuid128_create(&uuid, value + 5); 280 281 sdp_uuid2strn(&uuid, uuidstr, MAX_LEN_UUID_STR); 282 g_print("uuid = %s\n", uuidstr); 283 } 284 285 att_data_list_free(list); 286 287 /* Fetch remaining characteristics for the CURRENT primary service */ 288 gatt_discover_char(char_data->attrib, last + 1, char_data->end, 289 char_discovered_cb, char_data); 290 291 return; 292 293done: 294 g_free(char_data); 295 if (opt_listen == FALSE) 296 g_main_loop_quit(event_loop); 297} 298 299static gboolean characteristics(gpointer user_data) 300{ 301 GAttrib *attrib = user_data; 302 struct characteristic_data *char_data; 303 304 char_data = g_new(struct characteristic_data, 1); 305 char_data->attrib = attrib; 306 char_data->start = opt_start; 307 char_data->end = opt_end; 308 309 gatt_discover_char(attrib, opt_start, opt_end, char_discovered_cb, 310 char_data); 311 312 return FALSE; 313} 314 315static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen, 316 gpointer user_data) 317{ 318 uint8_t value[ATT_MTU]; 319 int i, vlen; 320 321 if (status != 0) { 322 g_printerr("Characteristic value/descriptor read failed: %s\n", 323 att_ecode2str(status)); 324 goto done; 325 } 326 if (!dec_read_resp(pdu, plen, value, &vlen)) { 327 g_printerr("Protocol error\n"); 328 goto done; 329 } 330 g_print("Characteristic value/descriptor: "); 331 for (i = 0; i < vlen; i++) 332 g_print("%02x ", value[i]); 333 g_print("\n"); 334 335done: 336 if (opt_listen == FALSE) 337 g_main_loop_quit(event_loop); 338} 339 340static gboolean characteristics_read(gpointer user_data) 341{ 342 GAttrib *attrib = user_data; 343 344 gatt_read_char(attrib, opt_handle, char_read_cb, attrib); 345 346 return FALSE; 347} 348 349static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen, 350 gpointer user_data) 351{ 352 struct att_data_list *list; 353 guint8 format; 354 int i; 355 356 if (status != 0) { 357 g_printerr("Discover all characteristic descriptors failed: " 358 "%s\n", att_ecode2str(status)); 359 goto done; 360 } 361 362 list = dec_find_info_resp(pdu, plen, &format); 363 if (list == NULL) 364 goto done; 365 366 for (i = 0; i < list->num; i++) { 367 char uuidstr[MAX_LEN_UUID_STR]; 368 uint16_t handle; 369 uint8_t *value; 370 uuid_t uuid; 371 372 value = list->data[i]; 373 handle = att_get_u16((uint16_t *) value); 374 375 if (format == 0x01) 376 sdp_uuid16_create(&uuid, att_get_u16((uint16_t *) 377 &value[2])); 378 else 379 sdp_uuid128_create(&uuid, &value[2]); 380 381 sdp_uuid2strn(&uuid, uuidstr, MAX_LEN_UUID_STR); 382 g_print("handle = 0x%04x, uuid = %s\n", handle, uuidstr); 383 } 384 385 att_data_list_free(list); 386 387done: 388 if (opt_listen == FALSE) 389 g_main_loop_quit(event_loop); 390} 391 392static gboolean characteristics_desc(gpointer user_data) 393{ 394 GAttrib *attrib = user_data; 395 396 gatt_find_info(attrib, opt_start, opt_end, char_desc_cb, NULL); 397 398 return FALSE; 399} 400 401static GOptionEntry primary_char_options[] = { 402 { "start", 's' , 0, G_OPTION_ARG_INT, &opt_start, 403 "Starting handle(optional)", "0x0001" }, 404 { "end", 'e' , 0, G_OPTION_ARG_INT, &opt_end, 405 "Ending handle(optional)", "0xffff" }, 406 { NULL }, 407}; 408 409static GOptionEntry char_read_options[] = { 410 { "handle", 'a' , 0, G_OPTION_ARG_INT, &opt_handle, 411 "Read characteristic by handle(optional)", "0x0001" }, 412 {NULL}, 413}; 414 415static GOptionEntry gatt_options[] = { 416 { "primary", 0, 0, G_OPTION_ARG_NONE, &opt_primary, 417 "Primary Service Discovery", NULL }, 418 { "characteristics", 0, 0, G_OPTION_ARG_NONE, &opt_characteristics, 419 "Characteristics Discovery", NULL }, 420 { "char-read", 0, 0, G_OPTION_ARG_NONE, &opt_char_read, 421 "Characteristics Value/Descriptor Read", NULL }, 422 { "char-desc", 0, 0, G_OPTION_ARG_NONE, &opt_char_desc, 423 "Characteristics Descriptor Discovery", NULL }, 424 { "listen", 0, 0, G_OPTION_ARG_NONE, &opt_listen, 425 "Listen for notifications", NULL }, 426 { NULL }, 427}; 428 429static GOptionEntry options[] = { 430 { "adapter", 'i', 0, G_OPTION_ARG_STRING, &opt_src, 431 "Specify local adapter interface", "hciX" }, 432 { "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst, 433 "Specify remote Bluetooth address", "MAC" }, 434 { NULL }, 435}; 436 437int main(int argc, char *argv[]) 438{ 439 GOptionContext *context; 440 GOptionGroup *gatt_group, *params_group, *char_read_group; 441 GError *gerr = NULL; 442 GAttrib *attrib; 443 GIOChannel *chan; 444 GSourceFunc callback; 445 int ret = 0; 446 447 context = g_option_context_new(NULL); 448 g_option_context_add_main_entries(context, options, NULL); 449 450 /* GATT commands */ 451 gatt_group = g_option_group_new("gatt", "GATT commands", 452 "Show all GATT commands", NULL, NULL); 453 g_option_context_add_group(context, gatt_group); 454 g_option_group_add_entries(gatt_group, gatt_options); 455 456 /* Primary Services and Characteristics arguments */ 457 params_group = g_option_group_new("params", 458 "Primary Services/Characteristics arguments", 459 "Show all Primary Services/Characteristics arguments", 460 NULL, NULL); 461 g_option_context_add_group(context, params_group); 462 g_option_group_add_entries(params_group, primary_char_options); 463 464 /* Characteristics value/descriptor read arguments */ 465 char_read_group = g_option_group_new("char-read", 466 "Characteristics Value/Descriptor Read arguments", 467 "Show all Characteristics Value/Descriptor Read arguments", 468 NULL, NULL); 469 g_option_context_add_group(context, char_read_group); 470 g_option_group_add_entries(char_read_group, char_read_options); 471 472 if (g_option_context_parse(context, &argc, &argv, &gerr) == FALSE) { 473 g_printerr("%s\n", gerr->message); 474 g_error_free(gerr); 475 } 476 477 if (opt_primary) 478 callback = primary; 479 else if (opt_characteristics) 480 callback = characteristics; 481 else if (opt_char_read) 482 callback = characteristics_read; 483 else if (opt_char_desc) 484 callback = characteristics_desc; 485 else { 486 gchar *help = g_option_context_get_help(context, TRUE, NULL); 487 g_print("%s\n", help); 488 g_free(help); 489 ret = 1; 490 goto done; 491 } 492 493 chan = do_connect(); 494 if (chan == NULL) { 495 ret = 1; 496 goto done; 497 } 498 499 attrib = g_attrib_new(chan); 500 501 event_loop = g_main_loop_new(NULL, FALSE); 502 503 if (opt_listen) 504 g_idle_add(listen_start, attrib); 505 506 g_idle_add(callback, attrib); 507 508 g_main_loop_run(event_loop); 509 510 if (listen_watch) 511 g_attrib_unregister(attrib, listen_watch); 512 513 g_main_loop_unref(event_loop); 514 515 g_io_channel_unref(chan); 516 g_attrib_unref(attrib); 517 518done: 519 g_option_context_free(context); 520 g_free(opt_src); 521 g_free(opt_dst); 522 523 return ret; 524} 525