gatttool.c revision 765b7e0e566c6883652c87b57a6282d948b60df6
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27 28#include <errno.h> 29#include <glib.h> 30#include <stdlib.h> 31#include <unistd.h> 32#include <sys/un.h> 33#include <sys/socket.h> 34 35#include <bluetooth/bluetooth.h> 36#include <bluetooth/l2cap.h> 37#include <bluetooth/hci.h> 38#include <bluetooth/hci_lib.h> 39#include <bluetooth/sdp.h> 40#include <bluetooth/sdp_lib.h> 41 42#include "att.h" 43#include "gattrib.h" 44#include "gatt.h" 45 46#define GATT_UNIX_PATH "/var/run/gatt" 47#define GATT_PSM 27 48 49static gchar *opt_src = NULL; 50static gchar *opt_dst = NULL; 51static int opt_start = 0x0001; 52static int opt_end = 0xffff; 53static int opt_handle = 0x0001; 54static gboolean opt_unix = FALSE; 55static gboolean opt_primary = FALSE; 56static gboolean opt_characteristics = FALSE; 57static gboolean opt_char_value_read = 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 g_free(opt_src); 87 } else 88 bacpy(&sba, BDADDR_ANY); 89 90 sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); 91 if (sk < 0) { 92 err = errno; 93 g_printerr("L2CAP socket create failed: %s(%d)\n", 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", strerror(err), err); 104 close(sk); 105 return -err; 106 } 107 108 memset(&addr, 0, sizeof(addr)); 109 addr.l2_family = AF_BLUETOOTH; 110 bacpy(&addr.l2_bdaddr, &dba); 111 addr.l2_psm = htobs(GATT_PSM); 112 113 err = connect(sk, (struct sockaddr *) &addr, sizeof(addr)); 114 if (err < 0) { 115 err = errno; 116 g_printerr("L2CAP socket connect failed: %s(%d)\n", strerror(err), err); 117 close(sk); 118 return -err; 119 } 120 121 return sk; 122} 123 124static int unix_connect(const char *address) 125{ 126 struct sockaddr_un addr; 127 int sk, err; 128 129 memset(&addr, 0, sizeof(addr)); 130 addr.sun_family = PF_UNIX; 131 strncpy(addr.sun_path, address, sizeof(addr.sun_path) - 1); 132 133 sk = socket(AF_UNIX, SOCK_STREAM, 0); 134 if (sk < 0) { 135 err = errno; 136 g_printerr("Unix socket(%s) create failed: %s(%d)\n", address, 137 strerror(err), err); 138 return -err; 139 } 140 141 if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 142 err = errno; 143 g_printerr("Unix socket(%s) connect failed: %s(%d)\n", address, 144 strerror(err), err); 145 close(sk); 146 return -err; 147 } 148 149 return sk; 150} 151 152static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen, 153 gpointer user_data) 154{ 155 GAttrib *attrib = user_data; 156 unsigned int i; 157 uint8_t length; 158 uint16_t end, start; 159 guint atid; 160 161 if (status == ATT_ECODE_ATTR_NOT_FOUND) 162 goto done; 163 164 if (status != 0) { 165 g_printerr("Discover all primary services failed: %s\n", 166 att_ecode2str(status)); 167 goto done; 168 } 169 170 if (pdu[0] != ATT_OP_READ_BY_GROUP_RESP) { 171 g_printerr("Protocol error\n"); 172 goto done; 173 } 174 175 length = pdu[1]; 176 for (i = 2, end = 0; i < plen; i += length) { 177 uint16_t *p16; 178 179 p16 = (void *) &pdu[i]; 180 start = btohs(*p16); 181 p16++; 182 end = btohs(*p16); 183 p16++; 184 if (length == 6) { 185 uint16_t u16 = btohs(*p16); 186 187 g_print("Service => start: 0x%04x, end: 0x%04x, " 188 "uuid: 0x%04x\n", start, end, u16); 189 } else if (length == 20) { 190 /* FIXME: endianness */ 191 } else { 192 g_printerr("ATT: Invalid Length field\n"); 193 goto done; 194 } 195 } 196 197 if (end == 0) { 198 g_printerr("ATT: Invalid PDU format\n"); 199 goto done; 200 } 201 202 /* 203 * Discover all primary services sub-procedure shall send another 204 * Read by Group Type Request until Error Response is received and 205 * the Error Code is set to Attribute Not Found. 206 */ 207 atid = gatt_discover_primary(attrib, 208 end + 1, 0xffff, primary_cb, attrib); 209 if (atid == 0) 210 g_printerr("Discovery primary failed\n"); 211 212done: 213 g_attrib_unref(attrib); 214 g_main_loop_quit(event_loop); 215} 216 217static gboolean primary(gpointer user_data) 218{ 219 int sk; 220 guint atid; 221 GIOChannel *chan; 222 GAttrib *attrib; 223 224 if (opt_unix) 225 sk = unix_connect(GATT_UNIX_PATH); 226 else 227 sk = l2cap_connect(); 228 if (sk < 0) { 229 g_main_loop_quit(event_loop); 230 return FALSE; 231 } 232 233 chan = g_io_channel_unix_new(sk); 234 g_io_channel_set_flags(chan, G_IO_FLAG_NONBLOCK, NULL); 235 g_io_channel_set_close_on_unref(chan, TRUE); 236 attrib = g_attrib_new(chan); 237 238 atid = gatt_discover_primary(attrib, 0x0001, 0xffff, primary_cb, attrib); 239 if (atid == 0) 240 g_attrib_unref(attrib); 241 242 return FALSE; 243} 244 245static void char_discovered_cb(guint8 status, const guint8 *pdu, guint16 plen, 246 gpointer user_data) 247{ 248 struct characteristic_data *char_data = user_data; 249 struct att_data_list *list; 250 uint16_t last = char_data->start; 251 int i; 252 253 if (status == ATT_ECODE_ATTR_NOT_FOUND) 254 goto done; 255 256 if (status != 0) { 257 g_printerr("Discover all characteristics failed\n"); 258 goto done; 259 } 260 261 list = dec_read_by_type_resp(pdu, plen); 262 if (list == NULL) 263 return; 264 265 for (i = 0; i < list->num; i++) { 266 uint16_t *u16, length; 267 uint8_t *data; 268 int j; 269 270 u16 = (uint16_t *) list->data[i]; 271 272 /* Each element contains: handle and attribute value */ 273 length = list->len - sizeof(*u16); 274 last = btohs(*u16); 275 u16++; 276 277 data = (uint8_t *)u16; 278 g_print("handle = 0x%04x, length = %d, ", last, length); 279 g_print("permission = %02x, char value handle = %02x %02x, ", 280 *data, *(data + 1), *(data + 2)); 281 g_print("uuid = "); 282 for (j = 3; j < length; j++) { 283 data = (uint8_t *)u16 + j; 284 g_print("%02x ", *data); 285 } 286 g_print("\n"); 287 } 288 289 att_data_list_free(list); 290 291 /* Fetch remaining characteristics for the CURRENT primary service */ 292 gatt_discover_char(char_data->attrib, last + 1, char_data->end, 293 char_discovered_cb, char_data); 294 295done: 296 g_attrib_unref(char_data->attrib); 297 g_free(char_data); 298 g_main_loop_quit(event_loop); 299} 300 301static gboolean characteristics(gpointer user_data) 302{ 303 struct characteristic_data *char_data; 304 GAttrib *attrib; 305 GIOChannel *chan; 306 guint atid; 307 int sk; 308 309 if (opt_unix) 310 sk = unix_connect(GATT_UNIX_PATH); 311 else 312 sk = l2cap_connect(); 313 if (sk < 0) { 314 g_main_loop_quit(event_loop); 315 return FALSE; 316 } 317 318 chan = g_io_channel_unix_new(sk); 319 g_io_channel_set_flags(chan, G_IO_FLAG_NONBLOCK, NULL); 320 g_io_channel_set_close_on_unref(chan, TRUE); 321 attrib = g_attrib_new(chan); 322 323 char_data = g_new(struct characteristic_data, 1); 324 char_data->attrib = attrib; 325 char_data->start = opt_start; 326 char_data->end = opt_end; 327 328 atid = gatt_discover_char(attrib, opt_start, opt_end, 329 char_discovered_cb, char_data); 330 if (atid == 0) 331 g_attrib_unref(attrib); 332 333 return FALSE; 334} 335 336static void char_value_cb(guint8 status, const guint8 *pdu, guint16 plen, 337 gpointer user_data) 338{ 339 GAttrib *attrib = user_data; 340 uint8_t value[ATT_MTU]; 341 int i, vlen; 342 343 if (status != 0) { 344 g_printerr("Characteristic value read failed: %s\n", 345 att_ecode2str(status)); 346 goto done; 347 } 348 if (!dec_read_resp(pdu, plen, value, &vlen)) { 349 g_printerr("Protocol error\n"); 350 goto done; 351 } 352 g_print("Characteristic value: "); 353 for (i = 0; i < vlen; i++) 354 g_print("%02x ", value[i]); 355 g_print("\n"); 356 357done: 358 g_attrib_unref(attrib); 359 g_main_loop_quit(event_loop); 360} 361 362static gboolean characteristics_value(gpointer user_data) 363{ 364 GIOChannel *chan; 365 GAttrib *attrib; 366 int sk; 367 368 if (opt_unix) 369 sk = unix_connect(GATT_UNIX_PATH); 370 else 371 sk = l2cap_connect(); 372 if (sk < 0) { 373 g_main_loop_quit(event_loop); 374 return FALSE; 375 } 376 377 chan = g_io_channel_unix_new(sk); 378 g_io_channel_set_flags(chan, G_IO_FLAG_NONBLOCK, NULL); 379 g_io_channel_set_close_on_unref(chan, TRUE); 380 attrib = g_attrib_new(chan); 381 382 gatt_read_char(attrib, opt_handle, char_value_cb, attrib); 383 384 return FALSE; 385} 386 387static GOptionEntry primary_char_options[] = { 388 { "start", 's' , 0, G_OPTION_ARG_INT, &opt_start, 389 "Starting handle(optional)", "0x0000" }, 390 { "end", 'e' , 0, G_OPTION_ARG_INT, &opt_end, 391 "Ending handle(optional)", "0xffff" }, 392 { NULL }, 393}; 394 395static GOptionEntry char_value_read_options[] = { 396 { "handle", 'a' , 0, G_OPTION_ARG_INT, &opt_handle, 397 "Read characteristic by handle", "0xXXXX" }, 398 {NULL}, 399}; 400 401static GOptionEntry gatt_options[] = { 402 { "primary", 0, 0, G_OPTION_ARG_NONE, &opt_primary, 403 "Primary Service Discovery", NULL }, 404 { "characteristics", 0, 0, G_OPTION_ARG_NONE, &opt_characteristics, 405 "Characteristics Discovery", NULL }, 406 { "char-value-read", 0, 0, G_OPTION_ARG_NONE, &opt_char_value_read, 407 "Characteristics Value Read", NULL }, 408 { NULL }, 409}; 410 411static GOptionEntry options[] = { 412 { "unix", 'u', 0, G_OPTION_ARG_NONE, &opt_unix, 413 "Connect to server using Unix socket" , NULL }, 414 { "adapter", 'i', 0, G_OPTION_ARG_STRING, &opt_src, 415 "Specify local adapter interface", "hciX" }, 416 { "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst, 417 "Specify remote Bluetooth address", "MAC" }, 418 { NULL }, 419}; 420 421int main(int argc, char *argv[]) 422{ 423 GOptionContext *context; 424 GOptionGroup *gatt_group, *params_group, *char_value_read_group; 425 GError *gerr = NULL; 426 427 context = g_option_context_new(NULL); 428 g_option_context_add_main_entries(context, options, NULL); 429 430 /* GATT commands */ 431 gatt_group = g_option_group_new("gatt", "GATT commands", 432 "Show all GATT commands", NULL, NULL); 433 g_option_context_add_group(context, gatt_group); 434 g_option_group_add_entries(gatt_group, gatt_options); 435 436 /* Primary Services and Characteristics arguments */ 437 params_group = g_option_group_new("params", 438 "Primary Services/Characteristics arguments", 439 "Show all Primary Services/Characteristics arguments", 440 NULL, NULL); 441 g_option_context_add_group(context, params_group); 442 g_option_group_add_entries(params_group, primary_char_options); 443 444 /* Characteristics value by read argument */ 445 char_value_read_group = g_option_group_new("char-value", 446 "Characteristics Value Read arguments", 447 "Show all Characteristics Value Read arguments", 448 NULL, NULL); 449 g_option_context_add_group(context, char_value_read_group); 450 g_option_group_add_entries(char_value_read_group, 451 char_value_read_options); 452 453 if (g_option_context_parse(context, &argc, &argv, &gerr) == FALSE) { 454 g_printerr("%s\n", gerr->message); 455 g_error_free(gerr); 456 } 457 458 event_loop = g_main_loop_new(NULL, FALSE); 459 460 if (opt_primary) 461 g_idle_add(primary, NULL); 462 463 if (opt_characteristics) 464 g_idle_add(characteristics, NULL); 465 466 if (opt_char_value_read) 467 g_idle_add(characteristics_value, NULL); 468 469 g_main_loop_run(event_loop); 470 471 g_option_context_free(context); 472 473 return 0; 474} 475