hcidump.c revision 8d58fe98fb6efd353c91dc2520e5bf46d72358ba
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]\n");
56}
57
58void process_frames(int dev, int sock, int file)
59{
60	char *data, *ctrl, *frame;
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 (!(data = malloc(snap_len + DUMP_HDR_SIZE))) {
71		perror("Can't allocate data buffer");
72		exit(1);
73	}
74	dh = (void *) data;
75	frame = data + 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 = frame;
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			parse(in, frame, len);
113		} else {
114			/* Save dump */
115			dh->len = __cpu_to_le16(len);
116			dh->in  = in;
117			if (write_n(file, data, len + DUMP_HDR_SIZE) < 0) {
118				perror("Write error");
119				exit(1);
120			}
121		}
122	}
123}
124
125void read_dump(int file)
126{
127	struct dump_hdr dh;
128	char *data;
129	int err;
130
131	if (!(data = malloc(HCI_MAX_FRAME_SIZE))) {
132		perror("Can't allocate data buffer");
133		exit(1);
134	}
135
136	while (1) {
137		int len;
138
139		if ((err = read_n(file, (void *) &dh, DUMP_HDR_SIZE)) < 0)
140			goto failed;
141		if (!err) return;
142
143		len = __le16_to_cpu(dh.len);
144
145		if ((err = read_n(file, data, len)) < 0)
146			goto failed;
147		if (!err) return;
148
149		parse(dh.in, data, len);
150	}
151
152failed:
153	perror("Read failed");
154	exit(1);
155}
156
157int open_file(char *file, int mode)
158{
159	int f, flags;
160
161	if (mode == WRITE)
162		flags = O_WRONLY | O_CREAT | O_APPEND;
163	else
164		flags = O_RDONLY;
165
166	if ((f = open(file, flags)) < 0) {
167		perror("Can't open output file");
168		exit(1);
169	}
170	return f;
171}
172
173int open_socket(int dev)
174{
175	struct sockaddr_hci addr;
176	struct hci_filter flt;
177	int s, opt;
178
179	/* Create HCI socket */
180	if ((s=socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
181		perror("Can't create HCI socket");
182		exit(1);
183	}
184
185	opt = 1;
186	if (setsockopt(s, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
187		perror("Can't enable data direction info");
188		exit(1);
189	}
190
191	/* Setup filter */
192	flt.type_mask  = ~0;      // All packet types
193	flt.event_mask[0] = ~0L;  // All events
194	flt.event_mask[1] = ~0L;
195	if (setsockopt(s, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
196		perror("Can't set HCI filter");
197		exit(1);
198	}
199
200	/* Bind socket to the HCI device */
201	addr.hci_family = AF_BLUETOOTH;
202	addr.hci_dev = dev;
203	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
204		printf("Can't attach to device hci%d. %s(%d)\n",
205					dev, strerror(errno), errno);
206		exit(1);
207	}
208	return s;
209}
210
211int main(int argc, char *argv[])
212{
213	extern int optind, opterr, optopt;
214	extern char *optarg;
215	int  dev, opt;
216	long flags;
217	char *file = NULL;
218
219	dev = 0;
220	flags = 0;
221
222	while ((opt=getopt(argc, argv,"i:s:haw:r:")) != EOF) {
223		switch(opt) {
224		case 'i':
225			dev = atoi(optarg+3);
226			break;
227
228		case 'h':
229			flags |= DUMP_HEX;
230			break;
231
232		case 'a':
233			flags |= DUMP_ASCII;
234			break;
235
236		case 's':
237			snap_len = atoi(optarg);
238			break;
239
240		case 'w':
241			mode = WRITE;
242			file = strdup(optarg);
243			break;
244
245		case 'r':
246			mode = READ;
247			file = strdup(optarg);
248			break;
249
250		default:
251			usage();
252			exit(1);
253		}
254	}
255
256	printf("HCIDump - HCI packet analyzer ver %s.\n", VERSION);
257
258	switch (mode) {
259	case DUMP:
260		init_parser(flags);
261		process_frames(dev, open_socket(dev), -1);
262		break;
263
264	case WRITE:
265		process_frames(dev, open_socket(dev), open_file(file, mode));
266		break;
267
268	case READ:
269		init_parser(flags);
270		read_dump(open_file(file, mode));
271		break;
272	}
273	return 0;
274}
275