hcidump.c revision 38acf6c4b654265055359f113f5a301115ca0947
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};
81
82/* Default options */
83static int  device;
84static int  snap_len = SNAP_LEN;
85static int  defpsm = 0;
86static int  defcompid = DEFAULT_COMPID;
87static int  mode = PARSE;
88static int  permcheck = 1;
89static long flags;
90static long filter;
91static char *dump_file;
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
222		cmsg = CMSG_FIRSTHDR(&msg);
223		while (cmsg) {
224			switch (cmsg->cmsg_type) {
225			case HCI_CMSG_DIR:
226				frm.in = *((int *) CMSG_DATA(cmsg));
227				break;
228			case HCI_CMSG_TSTAMP:
229				frm.ts = *((struct timeval *) CMSG_DATA(cmsg));
230				break;
231			}
232			cmsg = CMSG_NXTHDR(&msg, cmsg);
233		}
234
235		frm.ptr = frm.data;
236		frm.len = frm.data_len;
237
238		switch (mode) {
239		case WRITE:
240		case SEND:
241			/* Save or send dump */
242			if (flags & DUMP_BTSNOOP) {
243				uint64_t ts;
244				uint8_t pkt_type = ((uint8_t *) frm.data)[0];
245				dp->size = htonl(frm.data_len);
246				dp->len  = dp->size;
247				dp->flags = ntohl(frm.in & 0x01);
248				dp->drops = 0;
249				ts = (frm.ts.tv_sec - 946684800ll) * 1000000ll + frm.ts.tv_usec;
250				dp->ts = hton64(ts + 0x00E03AB44A676000ll);
251				if (pkt_type == HCI_COMMAND_PKT ||
252						pkt_type == HCI_EVENT_PKT)
253					dp->flags |= ntohl(0x02);
254			} else {
255				dh->len = htobs(frm.data_len);
256				dh->in  = frm.in;
257				dh->ts_sec  = htobl(frm.ts.tv_sec);
258				dh->ts_usec = htobl(frm.ts.tv_usec);
259			}
260
261			if (write_n(fd, buf, frm.data_len + hdr_size) < 0) {
262				perror("Write error");
263				exit(1);
264			}
265			break;
266
267		default:
268			/* Parse and print */
269			parse(&frm);
270			break;
271		}
272	}
273}
274
275static void read_dump(int fd)
276{
277	struct hcidump_hdr dh;
278	struct btsnoop_pkt dp;
279	struct frame frm;
280	uint8_t pkt_type;
281	int err;
282
283	frm.data = malloc(HCI_MAX_FRAME_SIZE);
284	if (!frm.data) {
285		perror("Can't allocate data buffer");
286		exit(1);
287	}
288
289	while (1) {
290		if (parser.flags & DUMP_BTSNOOP)
291			err = read_n(fd, (void *) &dp, BTSNOOP_PKT_SIZE);
292		else
293			err = read_n(fd, (void *) &dh, HCIDUMP_HDR_SIZE);
294
295		if (err < 0)
296			goto failed;
297		if (!err)
298			return;
299
300		if (parser.flags & DUMP_BTSNOOP) {
301			switch (btsnoop_type) {
302			case 1001:
303				if (ntohl(dp.flags) & 0x02) {
304					if (ntohl(dp.flags) & 0x01)
305						pkt_type = HCI_EVENT_PKT;
306					else
307						pkt_type = HCI_COMMAND_PKT;
308				} else
309					pkt_type = HCI_ACLDATA_PKT;
310
311				((uint8_t *) frm.data)[0] = pkt_type;
312
313				frm.data_len = ntohl(dp.len) + 1;
314				err = read_n(fd, frm.data + 1, frm.data_len - 1);
315				break;
316
317			case 1002:
318				frm.data_len = ntohl(dp.len);
319				err = read_n(fd, frm.data, frm.data_len);
320				break;
321			}
322		} else {
323			frm.data_len = btohs(dh.len);
324			err = read_n(fd, frm.data, frm.data_len);
325		}
326
327		if (err < 0)
328			goto failed;
329		if (!err)
330			return;
331
332		frm.ptr = frm.data;
333		frm.len = frm.data_len;
334
335		if (parser.flags & DUMP_BTSNOOP) {
336			uint64_t ts;
337			frm.in = ntohl(dp.flags) & 0x01;
338			ts = ntoh64(dp.ts) - 0x00E03AB44A676000ll;
339			frm.ts.tv_sec = (ts / 1000000ll) + 946684800ll;
340			frm.ts.tv_usec = ts % 1000000ll;
341		} else {
342			frm.in = dh.in;
343			frm.ts.tv_sec  = btohl(dh.ts_sec);
344			frm.ts.tv_usec = btohl(dh.ts_usec);
345		}
346
347		parse(&frm);
348	}
349
350failed:
351	perror("Read failed");
352	exit(1);
353}
354
355static int open_file(char *file, int mode, unsigned long flags)
356{
357	struct btsnoop_hdr hdr;
358	int fd, len, open_flags;
359
360	if (mode == WRITE) {
361		if (flags & DUMP_BTSNOOP)
362			open_flags = O_WRONLY | O_CREAT;
363		else
364			open_flags = O_WRONLY | O_CREAT | O_APPEND;
365	} else
366		open_flags = O_RDONLY;
367
368	fd = open(file, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
369	if (fd < 0) {
370		perror("Can't open dump file");
371		exit(1);
372	}
373
374	if (mode == READ) {
375		len = read(fd, &hdr, BTSNOOP_HDR_SIZE);
376		if (len != BTSNOOP_HDR_SIZE) {
377			lseek(fd, 0, SEEK_SET);
378			return fd;
379		}
380
381		if (!memcmp(hdr.id, btsnoop_id, sizeof(btsnoop_id))) {
382			parser.flags |= DUMP_BTSNOOP;
383
384			btsnoop_version = ntohl(hdr.version);
385			btsnoop_type = ntohl(hdr.type);
386
387			printf("btsnoop version: %d datalink type: %d\n",
388						btsnoop_version, btsnoop_type);
389
390			if (btsnoop_version != 1) {
391				fprintf(stderr, "Unsupported BTSnoop version\n");
392				exit(1);
393			}
394
395			if (btsnoop_type != 1001 && btsnoop_type != 1002) {
396				fprintf(stderr, "Unsupported BTSnoop datalink type\n");
397				exit(1);
398			}
399		} else {
400			parser.flags &= ~DUMP_BTSNOOP;
401			lseek(fd, 0, SEEK_SET);
402			return fd;
403		}
404	} else {
405		if (flags & DUMP_BTSNOOP) {
406			btsnoop_version = 1;
407			btsnoop_type = 1002;
408
409			memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
410			hdr.version = htonl(btsnoop_version);
411			hdr.type = htonl(btsnoop_type);
412
413			printf("btsnoop version: %d datalink type: %d\n",
414						btsnoop_version, btsnoop_type);
415
416			len = write(fd, &hdr, BTSNOOP_HDR_SIZE);
417			if (len < 0) {
418				perror("Can't create dump header");
419				exit(1);
420			}
421
422			if (len != BTSNOOP_HDR_SIZE) {
423				fprintf(stderr, "Header size mismatch\n");
424				exit(1);
425			}
426		}
427	}
428
429	return fd;
430}
431
432static int open_socket(int dev, unsigned long flags)
433{
434	struct sockaddr_hci addr;
435	struct hci_filter flt;
436	struct hci_dev_info di;
437	int sk, dd, opt;
438
439	if (permcheck && dev != HCI_DEV_NONE) {
440		dd = hci_open_dev(dev);
441		if (dd < 0) {
442			perror("Can't open device");
443			exit(1);
444		}
445
446		if (hci_devinfo(dev, &di) < 0) {
447			perror("Can't get device info");
448			exit(1);
449		}
450
451		opt = hci_test_bit(HCI_RAW, &di.flags);
452		if (ioctl(dd, HCISETRAW, opt) < 0) {
453			if (errno == EACCES) {
454				perror("Can't access device");
455				exit(1);
456			}
457		}
458
459		hci_close_dev(dd);
460	}
461
462	/* Create HCI socket */
463	sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
464	if (sk < 0) {
465		perror("Can't create raw socket");
466		exit(1);
467	}
468
469	opt = 1;
470	if (setsockopt(sk, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
471		perror("Can't enable data direction info");
472		exit(1);
473	}
474
475	opt = 1;
476	if (setsockopt(sk, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
477		perror("Can't enable time stamp");
478		exit(1);
479	}
480
481	/* Setup filter */
482	hci_filter_clear(&flt);
483	hci_filter_all_ptypes(&flt);
484	hci_filter_all_events(&flt);
485	if (setsockopt(sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
486		perror("Can't set filter");
487		exit(1);
488	}
489
490	/* Bind socket to the HCI device */
491	addr.hci_family = AF_BLUETOOTH;
492	addr.hci_dev = dev;
493	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
494		printf("Can't attach to device hci%d. %s(%d)\n",
495					dev, strerror(errno), errno);
496		exit(1);
497	}
498
499	return sk;
500}
501
502static int open_connection(in_addr_t addr, in_port_t port)
503{
504	struct sockaddr_in sa;
505	int sk, opt;
506
507	sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
508	if (sk < 0) {
509		perror("Can't create inet socket");
510		exit(1);
511	}
512
513	opt = 1;
514	setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
515
516	sa.sin_family = AF_INET;
517	sa.sin_addr.s_addr = htonl(INADDR_ANY);
518	sa.sin_port = htons(0);
519	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
520		perror("Can't bind inet socket");
521		close(sk);
522		exit(1);
523	}
524
525	sa.sin_family = AF_INET;
526	sa.sin_addr.s_addr = htonl(addr);
527	sa.sin_port = htons(port);
528	if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
529		perror("Can't connect inet socket");
530		close(sk);
531		exit(1);
532	}
533
534	return sk;
535}
536
537static int wait_connection(in_addr_t addr, in_port_t port)
538{
539	struct sockaddr_in sa;
540	struct hostent *host;
541	socklen_t len;
542	int sk, nsk, opt;
543
544	sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
545	if (sk < 0) {
546		perror("Can't create inet socket");
547		exit(1);
548	}
549
550	opt = 1;
551	setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
552
553	sa.sin_family = AF_INET;
554	sa.sin_addr.s_addr = htonl(addr);
555	sa.sin_port = htons(port);
556	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
557		perror("Can't bind inet socket");
558		close(sk);
559		exit(1);
560	}
561
562	host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET);
563	printf("device: %s:%d snap_len: %d filter: 0x%lx\n",
564		host ? host->h_name : inet_ntoa(sa.sin_addr),
565		ntohs(sa.sin_port), snap_len, filter);
566
567	if (listen(sk, 1)) {
568		perror("Can't listen on inet socket");
569		close(sk);
570		exit(1);
571	}
572
573	len = sizeof(sa);
574	nsk = accept(sk, (struct sockaddr *) &sa, &len);
575	if (nsk < 0) {
576		perror("Can't accept new inet socket");
577		close(sk);
578		exit(1);
579	}
580
581	host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET);
582	printf("device: %s snap_len: %d filter: 0x%lx\n",
583		host ? host->h_name : inet_ntoa(sa.sin_addr), snap_len, filter);
584
585	close(sk);
586
587	return nsk;
588}
589
590static struct {
591	char *name;
592	int  flag;
593} filters[] = {
594	{ "lmp",	FILT_LMP	},
595	{ "hci",	FILT_HCI	},
596	{ "sco",	FILT_SCO	},
597	{ "l2cap",	FILT_L2CAP	},
598	{ "rfcomm",	FILT_RFCOMM	},
599	{ "sdp",	FILT_SDP	},
600	{ "bnep",	FILT_BNEP	},
601	{ "cmtp",	FILT_CMTP	},
602	{ "hidp",	FILT_HIDP	},
603	{ "hcrp",	FILT_HCRP	},
604	{ "avdtp",	FILT_AVDTP	},
605	{ "obex",	FILT_OBEX	},
606	{ "capi",	FILT_CAPI	},
607	{ "csr",	FILT_CSR	},
608	{ "dga",	FILT_DGA	},
609	{ 0 }
610};
611
612static void parse_filter(int argc, char **argv)
613{
614	int i,n;
615
616	for (i = 0; i < argc; i++) {
617		for (n = 0; filters[n].name; n++) {
618			if (!strcasecmp(filters[n].name, argv[i])) {
619				filter |= filters[n].flag;
620				break;
621			}
622		}
623	}
624}
625
626static void usage(void)
627{
628	printf(
629	"Usage: hcidump [OPTION...] [filter]\n"
630	"  -i, --device=hci_dev       HCI device\n"
631	"  -l, --snap-len=len         Snap len (in bytes)\n"
632	"  -p, --psm=psm              Default PSM\n"
633	"  -m, --manufacturer=compid  Default manufacturer\n"
634	"  -w, --save-dump=file       Save dump to a file\n"
635	"  -r, --read-dump=file       Read dump from a file\n"
636	"  -s, --send-dump=host       Send dump to a host\n"
637	"  -n, --recv-dump=host       Receive dump on a host\n"
638	"  -t, --ts                   Display time stamps\n"
639	"  -a, --ascii                Dump data in ascii\n"
640	"  -x, --hex                  Dump data in hex\n"
641	"  -X, --ext                  Dump data in hex and ascii\n"
642	"  -R, --raw                  Dump raw data\n"
643	"  -C, --cmtp=psm             PSM for CMTP\n"
644	"  -H, --hcrp=psm             PSM for HCRP\n"
645	"  -O, --obex=channel         Channel for OBEX\n"
646	"  -B, --btsnoop              Use BTSnoop file format\n"
647	"  -V, --verbose              Verbose decoding\n"
648	"  -h, --help                 Give this help list\n"
649	"      --usage                Give a short usage message\n"
650	);
651}
652
653static struct option main_options[] = {
654	{ "device",		1, 0, 'i' },
655	{ "snap-len",		1, 0, 'l' },
656	{ "psm",		1, 0, 'p' },
657	{ "manufacturer",	1, 0, 'm' },
658	{ "save-dump",		1, 0, 'w' },
659	{ "read-dump",		1, 0, 'r' },
660	{ "send-dump",		1, 0, 's' },
661	{ "recv-dump",		1, 0, 'n' },
662	{ "timestamp",		0, 0, 't' },
663	{ "ascii",		0, 0, 'a' },
664	{ "hex",		0, 0, 'x' },
665	{ "ext",		0, 0, 'X' },
666	{ "raw",		0, 0, 'R' },
667	{ "cmtp",		1, 0, 'C' },
668	{ "hcrp",		1, 0, 'H' },
669	{ "obex",		1, 0, 'O' },
670	{ "btsnoop",		0, 0, 'B' },
671	{ "verbose",		0, 0, 'V' },
672	{ "help",		0, 0, 'h' },
673	{ 0 }
674};
675
676int main(int argc, char *argv[])
677{
678	struct hostent *host;
679	struct in_addr addr;
680	int opt;
681
682	printf("HCI sniffer - Bluetooth packet analyzer ver %s\n", VERSION);
683
684	while ((opt=getopt_long(argc, argv, "i:l:p:m:w:r:s:n:taxXRC:H:O:BVZh", main_options, NULL)) != -1) {
685		switch(opt) {
686		case 'i':
687			if (strcasecmp(optarg, "none"))
688				device = atoi(optarg + 3);
689			else
690				device = HCI_DEV_NONE;
691			break;
692
693		case 'l':
694			snap_len = atoi(optarg);
695			break;
696
697		case 'p':
698			defpsm = atoi(optarg);
699			break;
700
701		case 'm':
702			defcompid = atoi(optarg);
703			break;
704
705		case 'w':
706			mode = WRITE;
707			dump_file = strdup(optarg);
708			break;
709
710		case 'r':
711			mode = READ;
712			dump_file = strdup(optarg);
713			break;
714
715		case 's':
716			mode = SEND;
717			host = gethostbyname(optarg);
718			if (host) {
719				bcopy(host->h_addr, &addr, sizeof(struct in_addr));
720				dump_addr = ntohl(addr.s_addr);
721				dump_port = DEFAULT_PORT;
722			} else {
723				dump_addr = INADDR_LOOPBACK;
724				dump_port = DEFAULT_PORT;
725			}
726			break;
727
728		case 'n':
729			mode = RECEIVE;
730			host = gethostbyname(optarg);
731			if (host) {
732				bcopy(host->h_addr, &addr, sizeof(struct in_addr));
733				dump_addr = ntohl(addr.s_addr);
734				dump_port = DEFAULT_PORT;
735			} else {
736				dump_addr = INADDR_LOOPBACK;
737				dump_port = DEFAULT_PORT;
738			}
739			break;
740
741		case 't':
742			flags |= DUMP_TSTAMP;
743			break;
744
745		case 'a':
746			flags |= DUMP_ASCII;
747			break;
748
749		case 'x':
750			flags |= DUMP_HEX;
751			break;
752
753		case 'X':
754			flags |= DUMP_EXT;
755			break;
756
757		case 'R':
758			flags |= DUMP_RAW;
759			break;
760
761		case 'C':
762			set_proto(0, atoi(optarg), 0, SDP_UUID_CMTP);
763			break;
764
765		case 'H':
766			set_proto(0, atoi(optarg), 0, SDP_UUID_HARDCOPY_CONTROL_CHANNEL);
767			break;
768
769		case 'O':
770			set_proto(0, 0, atoi(optarg), SDP_UUID_OBEX);
771			break;
772
773		case 'B':
774			flags |= DUMP_BTSNOOP;
775			break;
776
777		case 'V':
778			flags |= DUMP_VERBOSE;
779			break;
780
781		case 'Z':
782			permcheck = 0;
783			break;
784
785		case 'h':
786		default:
787			usage();
788			exit(0);
789		}
790	}
791
792	argc -= optind;
793	argv += optind;
794	optind = 0;
795
796	if (argc > 0)
797		parse_filter(argc, argv);
798
799	/* Default settings */
800	if (!filter)
801		filter = ~0L;
802
803	switch (mode) {
804	case PARSE:
805		init_parser(flags, filter, defpsm, defcompid);
806		process_frames(device, open_socket(device, flags), -1, flags);
807		break;
808
809	case READ:
810		init_parser(flags, filter, defpsm, defcompid);
811		read_dump(open_file(dump_file, mode, flags));
812		break;
813
814	case WRITE:
815		process_frames(device, open_socket(device, flags),
816				open_file(dump_file, mode, flags), flags);
817		break;
818
819	case RECEIVE:
820		init_parser(flags, filter, defpsm, defcompid);
821		read_dump(wait_connection(dump_addr, dump_port));
822		break;
823
824	case SEND:
825		process_frames(device, open_socket(device, flags),
826				open_connection(dump_addr, dump_port), flags);
827		break;
828	}
829
830	return 0;
831}
832