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