hcidump.c revision 174f39016a9aa77cda60ee578f535c8c026ef787
1/*
2	HCIDump - HCI packet analyzer
3	Copyright (C) 2000-2001 Maxim Krasnyansky <maxk@qualcomm.com>
4
5	This program is free software; you can redistribute it and/or modify
6	it under the terms of the GNU General Public License version 2 as
7	published by the Free Software Foundation;
8
9	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10	OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12	IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM,
13	OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
14	RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15	NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
16	USE OR PERFORMANCE OF THIS SOFTWARE.
17
18	ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS,
19	TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED.
20*/
21
22/*
23 * $Id$
24 */
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <termios.h>
30#include <fcntl.h>
31#include <sys/ioctl.h>
32#include <sys/socket.h>
33#include <sys/types.h>
34#include <sys/uio.h>
35#include <errno.h>
36#include <string.h>
37
38#include <asm/types.h>
39
40#include <bluetooth/bluetooth.h>
41#include <bluetooth/hci.h>
42#include <bluetooth/l2cap.h>
43
44#include "parser.h"
45#include "hcidump.h"
46
47/* Default options */
48int snap_len = SNAP_LEN;
49int mode = DUMP;
50
51void usage(void)
52{
53	printf("HCIDump - HCI packet analyzer ver %s\n", VERSION);
54	printf("Usage:\n");
55	printf("\thcidump <-i hciX> [-ah] [-w file] [-r file]\n");
56}
57
58void process_frames(int dev, int sock, int file)
59{
60	char *buf, *data, *ctrl;
61	struct cmsghdr *cmsg;
62	struct msghdr msg;
63	struct iovec  iv;
64	struct dump_hdr *dh;
65	int len, in;
66
67	if (snap_len < SNAP_LEN)
68		snap_len = SNAP_LEN;
69
70	if (!(buf = malloc(snap_len + DUMP_HDR_SIZE))) {
71		perror("Can't allocate data buffer");
72		exit(1);
73	}
74	dh = (void *) buf;
75	data = buf + DUMP_HDR_SIZE;
76
77	if (!(ctrl = malloc(100))) {
78		perror("Can't allocate control buffer");
79		exit(1);
80	}
81
82	printf("device: hci%d snap_len: %d filter: none\n", dev, snap_len);
83
84	while (1) {
85		iv.iov_base = data;
86		iv.iov_len  = snap_len;
87
88		msg.msg_iov = &iv;
89		msg.msg_iovlen = 1;
90		msg.msg_control = ctrl;
91		msg.msg_controllen = 100;
92
93		if ((len = recvmsg(sock, &msg, 0)) < 0) {
94			perror("Receive failed");
95			exit(1);
96		}
97
98		/* Process control message */
99		in = 0;
100		cmsg = CMSG_FIRSTHDR(&msg);
101		while (cmsg) {
102			switch (cmsg->cmsg_type) {
103			case HCI_CMSG_DIR:
104				in = *((int *)CMSG_DATA(cmsg));
105				break;
106			}
107			cmsg = CMSG_NXTHDR(&msg, cmsg);
108		}
109
110		if (file == -1) {
111			/* Parse and print */
112			struct frame frm;
113
114			frm.data = frm.ptr = data;
115			frm.data_len = frm.len = len;
116			frm.in = in;
117			frm.flags = 0;
118
119			parse(&frm);
120		} else {
121			/* Save dump */
122			dh->len = __cpu_to_le16(len);
123			dh->in  = in;
124			if (write_n(file, data, len + DUMP_HDR_SIZE) < 0) {
125				perror("Write error");
126				exit(1);
127			}
128		}
129	}
130}
131
132void read_dump(int file)
133{
134	struct dump_hdr dh;
135	char *data;
136	int err;
137
138	if (!(data = malloc(HCI_MAX_FRAME_SIZE))) {
139		perror("Can't allocate data buffer");
140		exit(1);
141	}
142
143	while (1) {
144		struct frame frm;
145		int len;
146
147		if ((err = read_n(file, (void *) &dh, DUMP_HDR_SIZE)) < 0)
148			goto failed;
149		if (!err) return;
150
151		len = __le16_to_cpu(dh.len);
152
153		if ((err = read_n(file, data, len)) < 0)
154			goto failed;
155		if (!err) return;
156
157		frm.data = frm.ptr = data;
158		frm.data_len = frm.len = len;
159		frm.in = dh.in;
160		frm.flags = 0;
161
162		parse(&frm);
163	}
164
165failed:
166	perror("Read failed");
167	exit(1);
168}
169
170int open_file(char *file, int mode)
171{
172	int f, flags;
173
174	if (mode == WRITE)
175		flags = O_WRONLY | O_CREAT | O_APPEND;
176	else
177		flags = O_RDONLY;
178
179	if ((f = open(file, flags)) < 0) {
180		perror("Can't open output file");
181		exit(1);
182	}
183	return f;
184}
185
186int open_socket(int dev)
187{
188	struct sockaddr_hci addr;
189	struct hci_filter flt;
190	int s, opt;
191
192	/* Create HCI socket */
193	if ((s=socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
194		perror("Can't create HCI socket");
195		exit(1);
196	}
197
198	opt = 1;
199	if (setsockopt(s, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
200		perror("Can't enable data direction info");
201		exit(1);
202	}
203
204	/* Setup filter */
205	flt.type_mask  = ~0;      // All packet types
206	flt.event_mask[0] = ~0L;  // All events
207	flt.event_mask[1] = ~0L;
208	if (setsockopt(s, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
209		perror("Can't set HCI filter");
210		exit(1);
211	}
212
213	/* Bind socket to the HCI device */
214	addr.hci_family = AF_BLUETOOTH;
215	addr.hci_dev = dev;
216	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
217		printf("Can't attach to device hci%d. %s(%d)\n",
218					dev, strerror(errno), errno);
219		exit(1);
220	}
221	return s;
222}
223
224int main(int argc, char *argv[])
225{
226	extern int optind, opterr, optopt;
227	extern char *optarg;
228	int  dev, opt;
229	long flags;
230	char *file = NULL;
231
232	dev = 0;
233	flags = 0;
234
235	while ((opt=getopt(argc, argv,"i:s:haw:r:")) != EOF) {
236		switch(opt) {
237		case 'i':
238			dev = atoi(optarg+3);
239			break;
240
241		case 'h':
242			flags |= DUMP_HEX;
243			break;
244
245		case 'a':
246			flags |= DUMP_ASCII;
247			break;
248
249		case 's':
250			snap_len = atoi(optarg);
251			break;
252
253		case 'w':
254			mode = WRITE;
255			file = strdup(optarg);
256			break;
257
258		case 'r':
259			mode = READ;
260			file = strdup(optarg);
261			break;
262
263		default:
264			usage();
265			exit(1);
266		}
267	}
268
269	printf("HCIDump - HCI packet analyzer ver %s.\n", VERSION);
270
271	switch (mode) {
272	case DUMP:
273		init_parser(flags);
274		process_frames(dev, open_socket(dev), -1);
275		break;
276
277	case WRITE:
278		process_frames(dev, open_socket(dev), open_file(file, mode));
279		break;
280
281	case READ:
282		init_parser(flags);
283		read_dump(open_file(file, mode));
284		break;
285	}
286	return 0;
287}
288