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