hcidump.c revision ebcc23ce2362fafd9f14703081c544f49b6853eb
1/*
2 *
3 *  Bluetooth packet analyzer - HCI sniffer
4 *
5 *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com>
6 *  Copyright (C) 2003-2005  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 *
23 *
24 *  $Id$
25 */
26
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30
31#include <stdio.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <stdlib.h>
35#include <unistd.h>
36#include <termios.h>
37#include <string.h>
38#include <getopt.h>
39#include <pwd.h>
40
41#include <sys/types.h>
42#include <sys/socket.h>
43#include <sys/ioctl.h>
44#include <sys/uio.h>
45#include <sys/stat.h>
46#include <arpa/inet.h>
47#include <netinet/in.h>
48#include <netdb.h>
49
50#include <bluetooth/bluetooth.h>
51#include <bluetooth/hci.h>
52#include <bluetooth/hci_lib.h>
53
54#include "parser/parser.h"
55#include "parser/sdp.h"
56
57#define SNAP_LEN 	HCI_MAX_FRAME_SIZE
58#define DEFAULT_PORT	10839;
59
60/* Modes */
61enum {
62	PARSE,
63	READ,
64	WRITE,
65	RECEIVE,
66	SEND
67};
68
69/* Default options */
70static int  device;
71static int  snap_len = SNAP_LEN;
72static int  defpsm = 0;
73static int  defcompid = DEFAULT_COMPID;
74static int  mode = PARSE;
75static long flags;
76static long filter;
77static char *dump_file;
78static in_addr_t dump_addr = INADDR_LOOPBACK;
79static in_port_t dump_port = DEFAULT_PORT;
80
81struct dump_hdr {
82	uint16_t	len;
83	uint8_t		in;
84	uint8_t		pad;
85	uint32_t	ts_sec;
86	uint32_t	ts_usec;
87} __attribute__ ((packed));
88#define DUMP_HDR_SIZE (sizeof(struct dump_hdr))
89
90static inline int read_n(int fd, char *buf, int len)
91{
92	register int t = 0, w;
93
94	while (len > 0) {
95		if ((w = read(fd, buf, len)) < 0) {
96			if (errno == EINTR || errno == EAGAIN)
97				continue;
98			return -1;
99		}
100		if (!w)
101			return 0;
102		len -= w; buf += w; t += w;
103	}
104	return t;
105}
106
107static inline int write_n(int fd, char *buf, int len)
108{
109	register int t = 0, w;
110
111	while (len > 0) {
112		if ((w = write(fd, buf, len)) < 0) {
113			if (errno == EINTR || errno == EAGAIN)
114				continue;
115			return -1;
116		}
117		if (!w)
118			return 0;
119		len -= w; buf += w; t += w;
120	}
121	return t;
122}
123
124static void process_frames(int dev, int sock, int file)
125{
126	struct cmsghdr *cmsg;
127	struct msghdr msg;
128	struct iovec  iv;
129	struct dump_hdr *dh;
130	struct frame frm;
131	char *buf, *ctrl;
132
133	if (snap_len < SNAP_LEN)
134		snap_len = SNAP_LEN;
135
136	if (!(buf = malloc(snap_len + DUMP_HDR_SIZE))) {
137		perror("Can't allocate data buffer");
138		exit(1);
139	}
140
141	dh = (void *) buf;
142	frm.data = buf + DUMP_HDR_SIZE;
143
144	if (!(ctrl = malloc(100))) {
145		perror("Can't allocate control buffer");
146		exit(1);
147	}
148
149	printf("device: hci%d snap_len: %d filter: 0x%lx\n",
150		dev, snap_len, filter);
151
152	memset(&msg, 0, sizeof(msg));
153
154	while (1) {
155		iv.iov_base = frm.data;
156		iv.iov_len  = snap_len;
157
158		msg.msg_iov = &iv;
159		msg.msg_iovlen = 1;
160		msg.msg_control = ctrl;
161		msg.msg_controllen = 100;
162
163		if ((frm.data_len = recvmsg(sock, &msg, 0)) < 0) {
164			perror("Receive failed");
165			exit(1);
166		}
167
168		/* Process control message */
169		frm.in = 0;
170		cmsg = CMSG_FIRSTHDR(&msg);
171		while (cmsg) {
172			switch (cmsg->cmsg_type) {
173			case HCI_CMSG_DIR:
174				frm.in = *((int *)CMSG_DATA(cmsg));
175				break;
176			case HCI_CMSG_TSTAMP:
177				frm.ts = *((struct timeval *)CMSG_DATA(cmsg));
178				break;
179			}
180			cmsg = CMSG_NXTHDR(&msg, cmsg);
181		}
182
183		frm.ptr = frm.data;
184		frm.len = frm.data_len;
185
186		switch (mode) {
187		case WRITE:
188		case SEND:
189			/* Save or send dump */
190			dh->len = htobs(frm.data_len);
191			dh->in  = frm.in;
192			dh->ts_sec  = htobl(frm.ts.tv_sec);
193			dh->ts_usec = htobl(frm.ts.tv_usec);
194			if (write_n(file, buf, frm.data_len + DUMP_HDR_SIZE) < 0) {
195				perror("Write error");
196				exit(1);
197			}
198			break;
199
200		default:
201			/* Parse and print */
202			parse(&frm);
203			break;
204		}
205	}
206}
207
208static void read_dump(int file)
209{
210	struct dump_hdr dh;
211	struct frame frm;
212	int err;
213
214	if (!(frm.data = malloc(HCI_MAX_FRAME_SIZE))) {
215		perror("Can't allocate data buffer");
216		exit(1);
217	}
218
219	while (1) {
220		if ((err = read_n(file, (void *) &dh, DUMP_HDR_SIZE)) < 0)
221			goto failed;
222		if (!err) return;
223
224		frm.data_len = btohs(dh.len);
225
226		if ((err = read_n(file, frm.data, frm.data_len)) < 0)
227			goto failed;
228		if (!err) return;
229
230		frm.ptr = frm.data;
231		frm.len = frm.data_len;
232		frm.in  = dh.in;
233		frm.ts.tv_sec  = btohl(dh.ts_sec);
234		frm.ts.tv_usec = btohl(dh.ts_usec);
235
236		parse(&frm);
237	}
238
239failed:
240	perror("Read failed");
241	exit(1);
242}
243
244static int open_file(char *file, int mode)
245{
246	int f, flags;
247
248	if (mode == WRITE)
249		flags = O_WRONLY | O_CREAT | O_APPEND;
250	else
251		flags = O_RDONLY;
252
253	if ((f = open(file, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
254		perror("Can't open output file");
255		exit(1);
256	}
257	return f;
258}
259
260static int open_socket(int dev, unsigned long flags)
261{
262	struct sockaddr_hci addr;
263	struct hci_filter flt;
264	int sk, opt;
265
266	/* Create HCI socket */
267	if ((sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
268		perror("Can't create HCI socket");
269		exit(1);
270	}
271
272	opt = 1;
273	if (setsockopt(sk, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
274		perror("Can't enable data direction info");
275		exit(1);
276	}
277
278	opt = 1;
279	if (setsockopt(sk, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
280		perror("Can't enable time stamp");
281		exit(1);
282	}
283
284	/* Setup filter */
285	hci_filter_clear(&flt);
286	if (flags & DUMP_BPA) {
287		hci_filter_set_ptype(HCI_VENDOR_PKT, &flt);
288		hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
289		hci_filter_set_event(EVT_VENDOR, &flt);
290	} else {
291		hci_filter_all_ptypes(&flt);
292		hci_filter_all_events(&flt);
293		hci_filter_clear_ptype(HCI_VENDOR_PKT, &flt);
294	}
295	if (setsockopt(sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
296		perror("Can't set HCI filter");
297		exit(1);
298	}
299
300	/* Bind socket to the HCI device */
301	addr.hci_family = AF_BLUETOOTH;
302	addr.hci_dev = dev;
303	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
304		printf("Can't attach to device hci%d. %s(%d)\n",
305					dev, strerror(errno), errno);
306		exit(1);
307	}
308
309	return sk;
310}
311
312static int open_connection(in_addr_t addr, in_port_t port)
313{
314	struct sockaddr_in sa;
315	int sk, opt;
316
317	if ((sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
318		perror("Can't create inet socket");
319		exit(1);
320	}
321
322	opt = 1;
323	setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
324
325	sa.sin_family = AF_INET;
326	sa.sin_addr.s_addr = htonl(INADDR_ANY);
327	sa.sin_port = htons(0);
328	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
329		perror("Can't bind inet socket");
330		close(sk);
331		exit(1);
332	}
333
334	sa.sin_family = AF_INET;
335	sa.sin_addr.s_addr = htonl(addr);
336	sa.sin_port = htons(port);
337	if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
338		perror("Can't connect inet socket");
339		close(sk);
340		exit(1);
341	}
342
343	return sk;
344}
345
346static int wait_connection(in_addr_t addr, in_port_t port)
347{
348	struct sockaddr_in sa;
349	struct hostent *host;
350	int sk, nsk, opt, len;
351
352	if ((sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
353		perror("Can't create inet socket");
354		exit(1);
355	}
356
357	opt = 1;
358	setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
359
360	sa.sin_family = AF_INET;
361	sa.sin_addr.s_addr = htonl(addr);
362	sa.sin_port = htons(port);
363	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
364		perror("Can't bind inet socket");
365		close(sk);
366		exit(1);
367	}
368
369	host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET);
370	printf("device: %s:%d snap_len: %d filter: 0x%lx\n",
371		host ? host->h_name : inet_ntoa(sa.sin_addr),
372		ntohs(sa.sin_port), snap_len, filter);
373
374	if (listen(sk, 1)) {
375		perror("Can't listen on inet socket");
376		close(sk);
377		exit(1);
378	}
379
380	len = sizeof(sa);
381	if ((nsk = accept(sk, (struct sockaddr *) &sa, &len)) < 0) {
382		perror("Can't accept new inet socket");
383		close(sk);
384		exit(1);
385	}
386
387	host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET);
388	printf("device: %s snap_len: %d filter: 0x%lx\n",
389		host ? host->h_name : inet_ntoa(sa.sin_addr), snap_len, filter);
390
391	close(sk);
392
393	return nsk;
394}
395
396static struct {
397	char *name;
398	int  flag;
399} filters[] = {
400	{ "hci",	FILT_HCI	},
401	{ "sco",	FILT_SCO	},
402	{ "l2cap",	FILT_L2CAP	},
403	{ "rfcomm",	FILT_RFCOMM	},
404	{ "sdp",	FILT_SDP	},
405	{ "bnep",	FILT_BNEP	},
406	{ "cmtp",	FILT_CMTP	},
407	{ "hidp",	FILT_HIDP	},
408	{ "hcrp",	FILT_HCRP	},
409	{ "avdtp",	FILT_AVDTP	},
410	{ "obex",	FILT_OBEX	},
411	{ "capi",	FILT_CAPI	},
412	{ 0 }
413};
414
415static void parse_filter(int argc, char **argv)
416{
417	int i,n;
418
419	for (i = 0; i < argc; i++) {
420		for (n = 0; filters[n].name; n++) {
421			if (!strcasecmp(filters[n].name, argv[i])) {
422				filter |= filters[n].flag;
423				break;
424			}
425		}
426	}
427}
428
429static void usage(void)
430{
431	printf(
432	"Usage: hcidump [OPTION...] [filter]\n"
433	"  -i, --device=hci_dev       HCI device\n"
434	"  -l, --snap-len=len         Snap len (in bytes)\n"
435	"  -p, --psm=psm              Default PSM\n"
436	"  -m, --manufacturer=compid  Default manufacturer\n"
437	"  -w, --save-dump=file       Save dump to a file\n"
438	"  -r, --read-dump=file       Read dump from a file\n"
439	"  -s, --send-dump=host       Send dump to a host\n"
440	"  -n, --recv-dump=host       Receive dump on a host\n"
441	"  -t, --ts                   Display time stamps\n"
442	"  -a, --ascii                Dump data in ascii\n"
443	"  -x, --hex                  Dump data in hex\n"
444	"  -X, --ext                  Dump data in hex and ascii\n"
445	"  -R, --raw                  Raw mode\n"
446	"  -B, --bpa                  BPA mode\n"
447	"  -C, --cmtp=psm             PSM for CMTP\n"
448	"  -H, --hcrp=psm             PSM for HCRP\n"
449	"  -O, --obex=channel         Channel for OBEX\n"
450	"  -V, --verbose              Verbose decoding\n"
451	"  -h, --help                 Give this help list\n"
452	"      --usage                Give a short usage message\n"
453	);
454}
455
456static struct option main_options[] = {
457	{ "device",		1, 0, 'i' },
458	{ "snap-len",		1, 0, 'l' },
459	{ "psm",		1, 0, 'p' },
460	{ "manufacturer",	1, 0, 'm' },
461	{ "save-dump",		1, 0, 'w' },
462	{ "read-dump",		1, 0, 'r' },
463	{ "send-dump",		1, 0, 's' },
464	{ "recv-dump",		1, 0, 'n' },
465	{ "timestamp",		0, 0, 't' },
466	{ "ascii",		0, 0, 'a' },
467	{ "hex",		0, 0, 'x' },
468	{ "ext",		0, 0, 'X' },
469	{ "raw",		0, 0, 'R' },
470	{ "bpa",		0, 0, 'B' },
471	{ "cmtp",		1, 0, 'C' },
472	{ "hcrp",		1, 0, 'H' },
473	{ "obex",		1, 0, 'O' },
474	{ "verbose",		0, 0, 'V' },
475	{ "help",		0, 0, 'h' },
476	{ 0 }
477};
478
479int main(int argc, char *argv[])
480{
481	struct hostent *host;
482	struct in_addr addr;
483	int opt;
484
485	printf("HCI sniffer - Bluetooth packet analyzer ver %s\n", VERSION);
486
487	while ((opt=getopt_long(argc, argv, "i:l:p:m:w:r:s:n:taxXRBC:H:O:Vh", main_options, NULL)) != -1) {
488		switch(opt) {
489		case 'i':
490			device = atoi(optarg + 3);
491			break;
492
493		case 'l':
494			snap_len = atoi(optarg);
495			break;
496
497		case 'p':
498			defpsm = atoi(optarg);
499			break;
500
501		case 'm':
502			defcompid = atoi(optarg);
503			break;
504
505		case 'w':
506			mode = WRITE;
507			dump_file = strdup(optarg);
508			break;
509
510		case 'r':
511			mode = READ;
512			dump_file = strdup(optarg);
513			break;
514
515		case 's':
516			mode = SEND;
517			host = gethostbyname(optarg);
518			if (host) {
519				bcopy(host->h_addr, &addr, sizeof(struct in_addr));
520				dump_addr = ntohl(addr.s_addr);
521				dump_port = DEFAULT_PORT;
522			} else {
523				dump_addr = INADDR_LOOPBACK;
524				dump_port = DEFAULT_PORT;
525			}
526			break;
527
528		case 'n':
529			mode = RECEIVE;
530			host = gethostbyname(optarg);
531			if (host) {
532				bcopy(host->h_addr, &addr, sizeof(struct in_addr));
533				dump_addr = ntohl(addr.s_addr);
534				dump_port = DEFAULT_PORT;
535			} else {
536				dump_addr = INADDR_LOOPBACK;
537				dump_port = DEFAULT_PORT;
538			}
539			break;
540
541		case 't':
542			flags |= DUMP_TSTAMP;
543			break;
544
545		case 'a':
546			flags |= DUMP_ASCII;
547			break;
548
549		case 'x':
550			flags |= DUMP_HEX;
551			break;
552
553		case 'X':
554			flags |= DUMP_EXT;
555			break;
556
557		case 'R':
558			flags |= DUMP_RAW;
559			break;
560
561		case 'B':
562			flags |= DUMP_BPA;
563			if (defcompid == DEFAULT_COMPID)
564				defcompid = 12;
565			break;
566
567		case 'C':
568			set_proto(0, atoi(optarg), 0, SDP_UUID_CMTP);
569			break;
570
571		case 'H':
572			set_proto(0, atoi(optarg), 0, SDP_UUID_HARDCOPY_CONTROL_CHANNEL);
573			break;
574
575		case 'O':
576			set_proto(0, 0, atoi(optarg), SDP_UUID_OBEX);
577			break;
578
579		case 'V':
580			flags |= DUMP_VERBOSE;
581			break;
582
583		case 'h':
584		default:
585			usage();
586			exit(0);
587		}
588	}
589
590	argc -= optind;
591	argv += optind;
592	optind = 0;
593
594	if (argc > 0)
595		parse_filter(argc, argv);
596
597	/* Default settings */
598	if (!filter)
599		filter = ~0L;
600
601	switch (mode) {
602	case PARSE:
603		init_parser(flags, filter, defpsm, defcompid);
604		process_frames(device, open_socket(device, flags), -1);
605		break;
606
607	case READ:
608		init_parser(flags, filter, defpsm, defcompid);
609		read_dump(open_file(dump_file, mode));
610		break;
611
612	case WRITE:
613		process_frames(device, open_socket(device, flags), open_file(dump_file, mode));
614		break;
615
616	case RECEIVE:
617		init_parser(flags, filter, defpsm, defcompid);
618		read_dump(wait_connection(dump_addr, dump_port));
619		break;
620
621	case SEND:
622		process_frames(device, open_socket(device, flags), open_connection(dump_addr, dump_port));
623		break;
624	}
625
626	return 0;
627}
628