hcidump.c revision 0033462dddb3b4adf56ea28680c1f135f25a4387
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 <unistd.h>
35#include <stdlib.h>
36#include <string.h>
37#include <getopt.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <sys/ioctl.h>
41#include <sys/socket.h>
42
43#include <bluetooth/bluetooth.h>
44#include <bluetooth/hci.h>
45#include <bluetooth/hci_lib.h>
46
47#include <arpa/inet.h>
48#include <netinet/in.h>
49#include <netdb.h>
50
51#include "parser/parser.h"
52#include "parser/sdp.h"
53
54#if __BYTE_ORDER == __LITTLE_ENDIAN
55static inline uint64_t ntoh64(uint64_t n)
56{
57	uint64_t h;
58	uint64_t tmp = ntohl(n & 0x00000000ffffffff);
59	h = ntohl(n >> 32);
60	h |= tmp << 32;
61	return h;
62}
63#elif __BYTE_ORDER == __BIG_ENDIAN
64#define ntoh64(x) (x)
65#else
66#error "Unknown byte order"
67#endif
68#define hton64(x) ntoh64(x)
69
70#define SNAP_LEN 	HCI_MAX_FRAME_SIZE
71#define DEFAULT_PORT	10839;
72
73/* Modes */
74enum {
75	PARSE,
76	READ,
77	WRITE,
78	RECEIVE,
79	SEND,
80	AUDIO
81};
82
83/* Default options */
84static int  device;
85static int  snap_len = SNAP_LEN;
86static int  defpsm = 0;
87static int  defcompid = DEFAULT_COMPID;
88static int  mode = PARSE;
89static int  permcheck = 1;
90static long flags;
91static long filter;
92static char *dump_file = NULL;
93static char *audio_file = NULL;
94static in_addr_t dump_addr = INADDR_LOOPBACK;
95static in_port_t dump_port = DEFAULT_PORT;
96
97struct hcidump_hdr {
98	uint16_t	len;
99	uint8_t		in;
100	uint8_t		pad;
101	uint32_t	ts_sec;
102	uint32_t	ts_usec;
103} __attribute__ ((packed));
104#define HCIDUMP_HDR_SIZE (sizeof(struct hcidump_hdr))
105
106struct btsnoop_hdr {
107	uint8_t		id[8];		/* Identification Pattern */
108	uint32_t	version;	/* Version Number = 1 */
109	uint32_t	type;		/* Datalink Type */
110} __attribute__ ((packed));
111#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))
112
113struct btsnoop_pkt {
114	uint32_t	size;		/* Original Length */
115	uint32_t	len;		/* Included Length */
116	uint32_t	flags;		/* Packet Flags */
117	uint32_t	drops;		/* Cumulative Drops */
118	uint64_t	ts;		/* Timestamp microseconds */
119	uint8_t		data[0];	/* Packet Data */
120} __attribute__ ((packed));
121#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
122
123static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
124
125static uint32_t btsnoop_version = 0;
126static uint32_t btsnoop_type = 0;
127
128static inline int read_n(int fd, char *buf, int len)
129{
130	register int t = 0, w;
131
132	while (len > 0) {
133		if ((w = read(fd, buf, len)) < 0) {
134			if (errno == EINTR || errno == EAGAIN)
135				continue;
136			return -1;
137		}
138		if (!w)
139			return 0;
140		len -= w; buf += w; t += w;
141	}
142	return t;
143}
144
145static inline int write_n(int fd, char *buf, int len)
146{
147	register int t = 0, w;
148
149	while (len > 0) {
150		if ((w = write(fd, buf, len)) < 0) {
151			if (errno == EINTR || errno == EAGAIN)
152				continue;
153			return -1;
154		}
155		if (!w)
156			return 0;
157		len -= w; buf += w; t += w;
158	}
159	return t;
160}
161
162static void process_frames(int dev, int sock, int fd, unsigned long flags)
163{
164	struct cmsghdr *cmsg;
165	struct msghdr msg;
166	struct iovec  iv;
167	struct hcidump_hdr *dh;
168	struct btsnoop_pkt *dp;
169	struct frame frm;
170	char *buf, *ctrl;
171	int len, hdr_size = HCIDUMP_HDR_SIZE;
172
173	if (snap_len < SNAP_LEN)
174		snap_len = SNAP_LEN;
175
176	if (flags & DUMP_BTSNOOP)
177		hdr_size = BTSNOOP_PKT_SIZE;
178
179	buf = malloc(snap_len + hdr_size);
180	if (!buf) {
181		perror("Can't allocate data buffer");
182		exit(1);
183	}
184
185	dh = (void *) buf;
186	dp = (void *) buf;
187	frm.data = buf + hdr_size;
188
189	ctrl = malloc(100);
190	if (!ctrl) {
191		perror("Can't allocate control buffer");
192		exit(1);
193	}
194
195	if (dev == HCI_DEV_NONE)
196		printf("system: ");
197	else
198		printf("device: hci%d ", dev);
199
200	printf("snap_len: %d filter: 0x%lx\n", snap_len, filter);
201
202	memset(&msg, 0, sizeof(msg));
203
204	while (1) {
205		iv.iov_base = frm.data;
206		iv.iov_len  = snap_len;
207
208		msg.msg_iov = &iv;
209		msg.msg_iovlen = 1;
210		msg.msg_control = ctrl;
211		msg.msg_controllen = 100;
212
213		len = recvmsg(sock, &msg, 0);
214		if (len < 0) {
215			perror("Receive failed");
216			exit(1);
217		}
218
219		/* Process control message */
220		frm.data_len = len;
221		frm.dev_id = dev;
222		frm.in = 0;
223		frm.audio_fd = parser.audio_fd;
224
225		cmsg = CMSG_FIRSTHDR(&msg);
226		while (cmsg) {
227			switch (cmsg->cmsg_type) {
228			case HCI_CMSG_DIR:
229				frm.in = *((int *) CMSG_DATA(cmsg));
230				break;
231			case HCI_CMSG_TSTAMP:
232				frm.ts = *((struct timeval *) CMSG_DATA(cmsg));
233				break;
234			}
235			cmsg = CMSG_NXTHDR(&msg, cmsg);
236		}
237
238		frm.ptr = frm.data;
239		frm.len = frm.data_len;
240
241		switch (mode) {
242		case WRITE:
243		case SEND:
244			/* Save or send dump */
245			if (flags & DUMP_BTSNOOP) {
246				uint64_t ts;
247				uint8_t pkt_type = ((uint8_t *) frm.data)[0];
248				dp->size = htonl(frm.data_len);
249				dp->len  = dp->size;
250				dp->flags = ntohl(frm.in & 0x01);
251				dp->drops = 0;
252				ts = (frm.ts.tv_sec - 946684800ll) * 1000000ll + frm.ts.tv_usec;
253				dp->ts = hton64(ts + 0x00E03AB44A676000ll);
254				if (pkt_type == HCI_COMMAND_PKT ||
255						pkt_type == HCI_EVENT_PKT)
256					dp->flags |= ntohl(0x02);
257			} else {
258				dh->len = htobs(frm.data_len);
259				dh->in  = frm.in;
260				dh->ts_sec  = htobl(frm.ts.tv_sec);
261				dh->ts_usec = htobl(frm.ts.tv_usec);
262			}
263
264			if (write_n(fd, buf, frm.data_len + hdr_size) < 0) {
265				perror("Write error");
266				exit(1);
267			}
268			break;
269
270		default:
271			/* Parse and print */
272			parse(&frm);
273			break;
274		}
275	}
276}
277
278static void read_dump(int fd)
279{
280	struct hcidump_hdr dh;
281	struct btsnoop_pkt dp;
282	struct frame frm;
283	uint8_t pkt_type;
284	int err;
285
286	frm.data = malloc(HCI_MAX_FRAME_SIZE);
287	if (!frm.data) {
288		perror("Can't allocate data buffer");
289		exit(1);
290	}
291
292	while (1) {
293		if (parser.flags & DUMP_BTSNOOP)
294			err = read_n(fd, (void *) &dp, BTSNOOP_PKT_SIZE);
295		else
296			err = read_n(fd, (void *) &dh, HCIDUMP_HDR_SIZE);
297
298		if (err < 0)
299			goto failed;
300		if (!err)
301			return;
302
303		if (parser.flags & DUMP_BTSNOOP) {
304			switch (btsnoop_type) {
305			case 1001:
306				if (ntohl(dp.flags) & 0x02) {
307					if (ntohl(dp.flags) & 0x01)
308						pkt_type = HCI_EVENT_PKT;
309					else
310						pkt_type = HCI_COMMAND_PKT;
311				} else
312					pkt_type = HCI_ACLDATA_PKT;
313
314				((uint8_t *) frm.data)[0] = pkt_type;
315
316				frm.data_len = ntohl(dp.len) + 1;
317				err = read_n(fd, frm.data + 1, frm.data_len - 1);
318				break;
319
320			case 1002:
321				frm.data_len = ntohl(dp.len);
322				err = read_n(fd, frm.data, frm.data_len);
323				break;
324			}
325		} else {
326			frm.data_len = btohs(dh.len);
327			err = read_n(fd, frm.data, frm.data_len);
328		}
329
330		if (err < 0)
331			goto failed;
332		if (!err)
333			return;
334
335		frm.ptr = frm.data;
336		frm.len = frm.data_len;
337
338		if (parser.flags & DUMP_BTSNOOP) {
339			uint64_t ts;
340			frm.in = ntohl(dp.flags) & 0x01;
341			ts = ntoh64(dp.ts) - 0x00E03AB44A676000ll;
342			frm.ts.tv_sec = (ts / 1000000ll) + 946684800ll;
343			frm.ts.tv_usec = ts % 1000000ll;
344		} else {
345			frm.in = dh.in;
346			frm.ts.tv_sec  = btohl(dh.ts_sec);
347			frm.ts.tv_usec = btohl(dh.ts_usec);
348		}
349
350		parse(&frm);
351	}
352
353failed:
354	perror("Read failed");
355	exit(1);
356}
357
358static int open_file(char *file, int mode, unsigned long flags)
359{
360	struct btsnoop_hdr hdr;
361	int fd, len, open_flags;
362
363	if (mode == WRITE || mode == AUDIO) {
364		if (flags & DUMP_BTSNOOP)
365			open_flags = O_WRONLY | O_CREAT;
366		else
367			open_flags = O_WRONLY | O_CREAT | O_APPEND;
368	} else
369		open_flags = O_RDONLY;
370
371	fd = open(file, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
372	if (fd < 0) {
373		perror("Can't open dump file");
374		exit(1);
375	}
376
377	if (mode == READ) {
378		len = read(fd, &hdr, BTSNOOP_HDR_SIZE);
379		if (len != BTSNOOP_HDR_SIZE) {
380			lseek(fd, 0, SEEK_SET);
381			return fd;
382		}
383
384		if (!memcmp(hdr.id, btsnoop_id, sizeof(btsnoop_id))) {
385			parser.flags |= DUMP_BTSNOOP;
386
387			btsnoop_version = ntohl(hdr.version);
388			btsnoop_type = ntohl(hdr.type);
389
390			printf("btsnoop version: %d datalink type: %d\n",
391						btsnoop_version, btsnoop_type);
392
393			if (btsnoop_version != 1) {
394				fprintf(stderr, "Unsupported BTSnoop version\n");
395				exit(1);
396			}
397
398			if (btsnoop_type != 1001 && btsnoop_type != 1002) {
399				fprintf(stderr, "Unsupported BTSnoop datalink type\n");
400				exit(1);
401			}
402		} else {
403			parser.flags &= ~DUMP_BTSNOOP;
404			lseek(fd, 0, SEEK_SET);
405			return fd;
406		}
407	} else {
408		if (flags & DUMP_BTSNOOP) {
409			btsnoop_version = 1;
410			btsnoop_type = 1002;
411
412			memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
413			hdr.version = htonl(btsnoop_version);
414			hdr.type = htonl(btsnoop_type);
415
416			printf("btsnoop version: %d datalink type: %d\n",
417						btsnoop_version, btsnoop_type);
418
419			len = write(fd, &hdr, BTSNOOP_HDR_SIZE);
420			if (len < 0) {
421				perror("Can't create dump header");
422				exit(1);
423			}
424
425			if (len != BTSNOOP_HDR_SIZE) {
426				fprintf(stderr, "Header size mismatch\n");
427				exit(1);
428			}
429		}
430	}
431
432	return fd;
433}
434
435static int open_socket(int dev, unsigned long flags)
436{
437	struct sockaddr_hci addr;
438	struct hci_filter flt;
439	struct hci_dev_info di;
440	int sk, dd, opt;
441
442	if (permcheck && dev != HCI_DEV_NONE) {
443		dd = hci_open_dev(dev);
444		if (dd < 0) {
445			perror("Can't open device");
446			exit(1);
447		}
448
449		if (hci_devinfo(dev, &di) < 0) {
450			perror("Can't get device info");
451			exit(1);
452		}
453
454		opt = hci_test_bit(HCI_RAW, &di.flags);
455		if (ioctl(dd, HCISETRAW, opt) < 0) {
456			if (errno == EACCES) {
457				perror("Can't access device");
458				exit(1);
459			}
460		}
461
462		hci_close_dev(dd);
463	}
464
465	/* Create HCI socket */
466	sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
467	if (sk < 0) {
468		perror("Can't create raw socket");
469		exit(1);
470	}
471
472	opt = 1;
473	if (setsockopt(sk, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
474		perror("Can't enable data direction info");
475		exit(1);
476	}
477
478	opt = 1;
479	if (setsockopt(sk, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
480		perror("Can't enable time stamp");
481		exit(1);
482	}
483
484	/* Setup filter */
485	hci_filter_clear(&flt);
486	hci_filter_all_ptypes(&flt);
487	hci_filter_all_events(&flt);
488	if (setsockopt(sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
489		perror("Can't set filter");
490		exit(1);
491	}
492
493	/* Bind socket to the HCI device */
494	addr.hci_family = AF_BLUETOOTH;
495	addr.hci_dev = dev;
496	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
497		printf("Can't attach to device hci%d. %s(%d)\n",
498					dev, strerror(errno), errno);
499		exit(1);
500	}
501
502	return sk;
503}
504
505static int open_connection(in_addr_t addr, in_port_t port)
506{
507	struct sockaddr_in sa;
508	int sk, opt;
509
510	sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
511	if (sk < 0) {
512		perror("Can't create inet socket");
513		exit(1);
514	}
515
516	opt = 1;
517	setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
518
519	sa.sin_family = AF_INET;
520	sa.sin_addr.s_addr = htonl(INADDR_ANY);
521	sa.sin_port = htons(0);
522	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
523		perror("Can't bind inet socket");
524		close(sk);
525		exit(1);
526	}
527
528	sa.sin_family = AF_INET;
529	sa.sin_addr.s_addr = htonl(addr);
530	sa.sin_port = htons(port);
531	if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
532		perror("Can't connect inet socket");
533		close(sk);
534		exit(1);
535	}
536
537	return sk;
538}
539
540static int wait_connection(in_addr_t addr, in_port_t port)
541{
542	struct sockaddr_in sa;
543	struct hostent *host;
544	socklen_t len;
545	int sk, nsk, opt;
546
547	sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
548	if (sk < 0) {
549		perror("Can't create inet socket");
550		exit(1);
551	}
552
553	opt = 1;
554	setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
555
556	sa.sin_family = AF_INET;
557	sa.sin_addr.s_addr = htonl(addr);
558	sa.sin_port = htons(port);
559	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
560		perror("Can't bind inet socket");
561		close(sk);
562		exit(1);
563	}
564
565	host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET);
566	printf("device: %s:%d snap_len: %d filter: 0x%lx\n",
567		host ? host->h_name : inet_ntoa(sa.sin_addr),
568		ntohs(sa.sin_port), snap_len, filter);
569
570	if (listen(sk, 1)) {
571		perror("Can't listen on inet socket");
572		close(sk);
573		exit(1);
574	}
575
576	len = sizeof(sa);
577	nsk = accept(sk, (struct sockaddr *) &sa, &len);
578	if (nsk < 0) {
579		perror("Can't accept new inet socket");
580		close(sk);
581		exit(1);
582	}
583
584	host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET);
585	printf("device: %s snap_len: %d filter: 0x%lx\n",
586		host ? host->h_name : inet_ntoa(sa.sin_addr), snap_len, filter);
587
588	close(sk);
589
590	return nsk;
591}
592
593static struct {
594	char *name;
595	int  flag;
596} filters[] = {
597	{ "lmp",	FILT_LMP	},
598	{ "hci",	FILT_HCI	},
599	{ "sco",	FILT_SCO	},
600	{ "l2cap",	FILT_L2CAP	},
601	{ "rfcomm",	FILT_RFCOMM	},
602	{ "sdp",	FILT_SDP	},
603	{ "bnep",	FILT_BNEP	},
604	{ "cmtp",	FILT_CMTP	},
605	{ "hidp",	FILT_HIDP	},
606	{ "hcrp",	FILT_HCRP	},
607	{ "avdtp",	FILT_AVDTP	},
608	{ "obex",	FILT_OBEX	},
609	{ "capi",	FILT_CAPI	},
610	{ "csr",	FILT_CSR	},
611	{ "dga",	FILT_DGA	},
612	{ 0 }
613};
614
615static void parse_filter(int argc, char **argv)
616{
617	int i,n;
618
619	for (i = 0; i < argc; i++) {
620		for (n = 0; filters[n].name; n++) {
621			if (!strcasecmp(filters[n].name, argv[i])) {
622				filter |= filters[n].flag;
623				break;
624			}
625		}
626	}
627}
628
629static void usage(void)
630{
631	printf(
632	"Usage: hcidump [OPTION...] [filter]\n"
633	"  -i, --device=hci_dev       HCI device\n"
634	"  -l, --snap-len=len         Snap len (in bytes)\n"
635	"  -p, --psm=psm              Default PSM\n"
636	"  -m, --manufacturer=compid  Default manufacturer\n"
637	"  -w, --save-dump=file       Save dump to a file\n"
638	"  -r, --read-dump=file       Read dump from a file\n"
639	"  -s, --send-dump=host       Send dump to a host\n"
640	"  -n, --recv-dump=host       Receive dump on a host\n"
641	"  -t, --ts                   Display time stamps\n"
642	"  -a, --ascii                Dump data in ascii\n"
643	"  -x, --hex                  Dump data in hex\n"
644	"  -X, --ext                  Dump data in hex and ascii\n"
645	"  -R, --raw                  Dump raw data\n"
646	"  -C, --cmtp=psm             PSM for CMTP\n"
647	"  -H, --hcrp=psm             PSM for HCRP\n"
648	"  -O, --obex=channel         Channel for OBEX\n"
649	"  -A, --audio=file           Extract SCO audio data\n"
650	"  -B, --btsnoop              Use BTSnoop file format\n"
651	"  -V, --verbose              Verbose decoding\n"
652	"  -h, --help                 Give this help list\n"
653	"      --usage                Give a short usage message\n"
654	);
655}
656
657static struct option main_options[] = {
658	{ "device",		1, 0, 'i' },
659	{ "snap-len",		1, 0, 'l' },
660	{ "psm",		1, 0, 'p' },
661	{ "manufacturer",	1, 0, 'm' },
662	{ "save-dump",		1, 0, 'w' },
663	{ "read-dump",		1, 0, 'r' },
664	{ "send-dump",		1, 0, 's' },
665	{ "recv-dump",		1, 0, 'n' },
666	{ "timestamp",		0, 0, 't' },
667	{ "ascii",		0, 0, 'a' },
668	{ "hex",		0, 0, 'x' },
669	{ "ext",		0, 0, 'X' },
670	{ "raw",		0, 0, 'R' },
671	{ "cmtp",		1, 0, 'C' },
672	{ "hcrp",		1, 0, 'H' },
673	{ "obex",		1, 0, 'O' },
674	{ "audio",		1, 0, 'A' },
675	{ "btsnoop",		0, 0, 'B' },
676	{ "verbose",		0, 0, 'V' },
677	{ "help",		0, 0, 'h' },
678	{ 0 }
679};
680
681int main(int argc, char *argv[])
682{
683	struct hostent *host;
684	struct in_addr addr;
685	int opt, fd = -1;
686
687	printf("HCI sniffer - Bluetooth packet analyzer ver %s\n", VERSION);
688
689	while ((opt=getopt_long(argc, argv, "i:l:p:m:w:r:s:n:taxXRC:H:O:A:BVZh", main_options, NULL)) != -1) {
690		switch(opt) {
691		case 'i':
692			if (strcasecmp(optarg, "none") && strcasecmp(optarg, "system"))
693				device = atoi(optarg + 3);
694			else
695				device = HCI_DEV_NONE;
696			break;
697
698		case 'l':
699			snap_len = atoi(optarg);
700			break;
701
702		case 'p':
703			defpsm = atoi(optarg);
704			break;
705
706		case 'm':
707			defcompid = atoi(optarg);
708			break;
709
710		case 'w':
711			mode = WRITE;
712			dump_file = strdup(optarg);
713			break;
714
715		case 'r':
716			mode = READ;
717			dump_file = strdup(optarg);
718			break;
719
720		case 's':
721			mode = SEND;
722			host = gethostbyname(optarg);
723			if (host) {
724				bcopy(host->h_addr, &addr, sizeof(struct in_addr));
725				dump_addr = ntohl(addr.s_addr);
726				dump_port = DEFAULT_PORT;
727			} else {
728				dump_addr = INADDR_LOOPBACK;
729				dump_port = DEFAULT_PORT;
730			}
731			break;
732
733		case 'n':
734			mode = RECEIVE;
735			host = gethostbyname(optarg);
736			if (host) {
737				bcopy(host->h_addr, &addr, sizeof(struct in_addr));
738				dump_addr = ntohl(addr.s_addr);
739				dump_port = DEFAULT_PORT;
740			} else {
741				dump_addr = INADDR_LOOPBACK;
742				dump_port = DEFAULT_PORT;
743			}
744			break;
745
746		case 't':
747			flags |= DUMP_TSTAMP;
748			break;
749
750		case 'a':
751			flags |= DUMP_ASCII;
752			break;
753
754		case 'x':
755			flags |= DUMP_HEX;
756			break;
757
758		case 'X':
759			flags |= DUMP_EXT;
760			break;
761
762		case 'R':
763			flags |= DUMP_RAW;
764			break;
765
766		case 'C':
767			set_proto(0, atoi(optarg), 0, SDP_UUID_CMTP);
768			break;
769
770		case 'H':
771			set_proto(0, atoi(optarg), 0, SDP_UUID_HARDCOPY_CONTROL_CHANNEL);
772			break;
773
774		case 'O':
775			set_proto(0, 0, atoi(optarg), SDP_UUID_OBEX);
776			break;
777
778		case 'A':
779			audio_file = strdup(optarg);
780			break;
781
782		case 'B':
783			flags |= DUMP_BTSNOOP;
784			break;
785
786		case 'V':
787			flags |= DUMP_VERBOSE;
788			break;
789
790		case 'Z':
791			permcheck = 0;
792			break;
793
794		case 'h':
795		default:
796			usage();
797			exit(0);
798		}
799	}
800
801	argc -= optind;
802	argv += optind;
803	optind = 0;
804
805	if (argc > 0)
806		parse_filter(argc, argv);
807
808	/* Default settings */
809	if (!filter)
810		filter = ~0L;
811
812	if (audio_file)
813		fd = open_file(audio_file, AUDIO, flags);
814
815	switch (mode) {
816	case PARSE:
817		init_parser(flags, filter, defpsm, defcompid, fd);
818		process_frames(device, open_socket(device, flags), -1, flags);
819		break;
820
821	case READ:
822		init_parser(flags, filter, defpsm, defcompid, fd);
823		read_dump(open_file(dump_file, mode, flags));
824		break;
825
826	case WRITE:
827		process_frames(device, open_socket(device, flags),
828				open_file(dump_file, mode, flags), flags);
829		break;
830
831	case RECEIVE:
832		init_parser(flags, filter, defpsm, defcompid, fd);
833		read_dump(wait_connection(dump_addr, dump_port));
834		break;
835
836	case SEND:
837		process_frames(device, open_socket(device, flags),
838				open_connection(dump_addr, dump_port), flags);
839		break;
840	}
841
842	return 0;
843}
844