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