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