xref: /freebsd/usr.sbin/usbdump/usbdump.c (revision 5dcd9c10612684d1c823670cbb5b4715028784e7)
1 /*-
2  * Copyright (c) 2010 Weongyo Jeong <weongyo@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  *
29  * $FreeBSD$
30  */
31 
32 #include <sys/param.h>
33 #include <sys/endian.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/utsname.h>
38 #include <net/if.h>
39 #include <net/bpf.h>
40 #include <dev/usb/usb.h>
41 #include <dev/usb/usb_pf.h>
42 #include <dev/usb/usbdi.h>
43 #include <assert.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <limits.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
51 #include <unistd.h>
52 
53 struct usbcap {
54 	int		fd;		/* fd for /dev/usbpf */
55 	u_int		bufsize;
56 	char		*buffer;
57 
58 	/* for -w option */
59 	int		wfd;
60 	/* for -r option */
61 	int		rfd;
62 };
63 
64 struct usbcap_filehdr {
65 	u_int		magic;
66 #define	USBCAP_FILEHDR_MAGIC	0x9a90000e
67 	u_char		major;
68 	u_char		minor;
69 	u_char		reserved[26];
70 } __packed;
71 
72 static int doexit = 0;
73 static int pkt_captured = 0;
74 static int verbose = 0;
75 static const char *i_arg = "usbus0";
76 static const char *r_arg = NULL;
77 static const char *w_arg = NULL;
78 static const char *errstr_table[USB_ERR_MAX] = {
79 	[USB_ERR_NORMAL_COMPLETION]	= "NORMAL_COMPLETION",
80 	[USB_ERR_PENDING_REQUESTS]	= "PENDING_REQUESTS",
81 	[USB_ERR_NOT_STARTED]		= "NOT_STARTED",
82 	[USB_ERR_INVAL]			= "INVAL",
83 	[USB_ERR_NOMEM]			= "NOMEM",
84 	[USB_ERR_CANCELLED]		= "CANCELLED",
85 	[USB_ERR_BAD_ADDRESS]		= "BAD_ADDRESS",
86 	[USB_ERR_BAD_BUFSIZE]		= "BAD_BUFSIZE",
87 	[USB_ERR_BAD_FLAG]		= "BAD_FLAG",
88 	[USB_ERR_NO_CALLBACK]		= "NO_CALLBACK",
89 	[USB_ERR_IN_USE]		= "IN_USE",
90 	[USB_ERR_NO_ADDR]		= "NO_ADDR",
91 	[USB_ERR_NO_PIPE]		= "NO_PIPE",
92 	[USB_ERR_ZERO_NFRAMES]		= "ZERO_NFRAMES",
93 	[USB_ERR_ZERO_MAXP]		= "ZERO_MAXP",
94 	[USB_ERR_SET_ADDR_FAILED]	= "SET_ADDR_FAILED",
95 	[USB_ERR_NO_POWER]		= "NO_POWER",
96 	[USB_ERR_TOO_DEEP]		= "TOO_DEEP",
97 	[USB_ERR_IOERROR]		= "IOERROR",
98 	[USB_ERR_NOT_CONFIGURED]	= "NOT_CONFIGURED",
99 	[USB_ERR_TIMEOUT]		= "TIMEOUT",
100 	[USB_ERR_SHORT_XFER]		= "SHORT_XFER",
101 	[USB_ERR_STALLED]		= "STALLED",
102 	[USB_ERR_INTERRUPTED]		= "INTERRUPTED",
103 	[USB_ERR_DMA_LOAD_FAILED]	= "DMA_LOAD_FAILED",
104 	[USB_ERR_BAD_CONTEXT]		= "BAD_CONTEXT",
105 	[USB_ERR_NO_ROOT_HUB]		= "NO_ROOT_HUB",
106 	[USB_ERR_NO_INTR_THREAD]	= "NO_INTR_THREAD",
107 	[USB_ERR_NOT_LOCKED]		= "NOT_LOCKED",
108 };
109 
110 static const char *xfertype_table[] = {
111 	[UE_CONTROL]			= "CTRL",
112 	[UE_ISOCHRONOUS]		= "ISOC",
113 	[UE_BULK]			= "BULK",
114 	[UE_INTERRUPT]			= "INTR"
115 };
116 
117 static void
118 handle_sigint(int sig)
119 {
120 
121 	(void)sig;
122 	doexit = 1;
123 }
124 
125 static void
126 print_flags(u_int32_t flags)
127 {
128 #define	PRINTFLAGS(name)			\
129 	if ((flags & USBPF_FLAG_##name) != 0)	\
130 		printf("%s ", #name);
131 	printf(" flags %#x", flags);
132 	printf(" < ");
133 	PRINTFLAGS(FORCE_SHORT_XFER);
134 	PRINTFLAGS(SHORT_XFER_OK);
135 	PRINTFLAGS(SHORT_FRAMES_OK);
136 	PRINTFLAGS(PIPE_BOF);
137 	PRINTFLAGS(PROXY_BUFFER);
138 	PRINTFLAGS(EXT_BUFFER);
139 	PRINTFLAGS(MANUAL_STATUS);
140 	PRINTFLAGS(NO_PIPE_OK);
141 	PRINTFLAGS(STALL_PIPE);
142 	printf(">\n");
143 #undef PRINTFLAGS
144 }
145 
146 static void
147 print_status(u_int32_t status)
148 {
149 #define	PRINTSTATUS(name)				\
150 	if ((status & USBPF_STATUS_##name) != 0)	\
151 		printf("%s ", #name);
152 
153 	printf(" status %#x", status);
154 	printf(" < ");
155 	PRINTSTATUS(OPEN);
156 	PRINTSTATUS(TRANSFERRING);
157 	PRINTSTATUS(DID_DMA_DELAY);
158 	PRINTSTATUS(DID_CLOSE);
159 	PRINTSTATUS(DRAINING);
160 	PRINTSTATUS(STARTED);
161 	PRINTSTATUS(BW_RECLAIMED);
162 	PRINTSTATUS(CONTROL_XFR);
163 	PRINTSTATUS(CONTROL_HDR);
164 	PRINTSTATUS(CONTROL_ACT);
165 	PRINTSTATUS(CONTROL_STALL);
166 	PRINTSTATUS(SHORT_FRAMES_OK);
167 	PRINTSTATUS(SHORT_XFER_OK);
168 #if USB_HAVE_BUSDMA
169 	PRINTSTATUS(BDMA_ENABLE);
170 	PRINTSTATUS(BDMA_NO_POST_SYNC);
171 	PRINTSTATUS(BDMA_SETUP);
172 #endif
173 	PRINTSTATUS(ISOCHRONOUS_XFR);
174 	PRINTSTATUS(CURR_DMA_SET);
175 	PRINTSTATUS(CAN_CANCEL_IMMED);
176 	PRINTSTATUS(DOING_CALLBACK);
177 	printf(">\n");
178 #undef PRINTSTATUS
179 }
180 
181 /*
182  * Display a region in traditional hexdump format.
183  */
184 static void
185 hexdump(const char *region, size_t len)
186 {
187 	const char *line;
188 	int x;
189 	int c;
190 #define EMIT(fmt, ...)	do {		\
191 	printf(fmt,## __VA_ARGS__);	\
192 } while (0)
193 
194 	for (line = region; line < (region + len); line += 16) {
195 		EMIT(" %04lx  ", (long) (line - region));
196 		for (x = 0; x < 16; x++) {
197 			if ((line + x) < (region + len))
198 				EMIT("%02x ", *(const u_int8_t *)(line + x));
199 			else
200 				EMIT("-- ");
201 			if (x == 7)
202 				EMIT(" ");
203 		}
204 		EMIT(" |");
205 		for (x = 0; x < 16; x++) {
206 			if ((line + x) < (region + len)) {
207 				c = *(const u_int8_t *)(line + x);
208 				/* !isprint(c) */
209 				if ((c < ' ') || (c > '~'))
210 					c = '.';
211 				EMIT("%c", c);
212 			} else
213 				EMIT(" ");
214 		}
215 		EMIT("|\n");
216 	}
217 #undef EMIT
218 }
219 
220 static void
221 print_apacket(const struct bpf_xhdr *hdr, struct usbpf_pkthdr *up,
222     const char *payload)
223 {
224 	struct tm *tm;
225 	struct timeval tv;
226 	size_t len;
227 	u_int32_t framelen, x;
228 	const char *ptr = payload;
229 	char buf[64];
230 
231 	/* A packet from the kernel is based on little endian byte order. */
232 	up->up_busunit = le32toh(up->up_busunit);
233 	up->up_flags = le32toh(up->up_flags);
234 	up->up_status = le32toh(up->up_status);
235 	up->up_length = le32toh(up->up_length);
236 	up->up_frames = le32toh(up->up_frames);
237 	up->up_error = le32toh(up->up_error);
238 	up->up_interval = le32toh(up->up_interval);
239 
240 	tv.tv_sec = hdr->bh_tstamp.bt_sec;
241 	tv.tv_usec = hdr->bh_tstamp.bt_frac;
242 	tm = localtime(&tv.tv_sec);
243 
244 	len = strftime(buf, sizeof(buf), "%H:%M:%S", tm);
245 	printf("%.*s.%06ju", (int)len, buf, tv.tv_usec);
246 	printf(" usbus%d.%d 0x%02x %s %s", up->up_busunit, up->up_address,
247 	    up->up_endpoint,
248 	    xfertype_table[up->up_xfertype],
249 	    up->up_type == USBPF_XFERTAP_SUBMIT ? "S" : "D");
250 	printf(" (%d/%d)", up->up_frames, up->up_length);
251 	if (up->up_type == USBPF_XFERTAP_DONE)
252 		printf(" %s", errstr_table[up->up_error]);
253 	if (up->up_xfertype == UE_BULK || up->up_xfertype == UE_ISOCHRONOUS)
254 		printf(" %d", up->up_interval);
255 	printf("\n");
256 
257 	if (verbose >= 1) {
258 		for (x = 0; x < up->up_frames; x++) {
259 			framelen = le32toh(*((const u_int32_t *)ptr));
260 			ptr += sizeof(u_int32_t);
261 			printf(" frame[%u] len %d\n", x, framelen);
262 			assert(framelen < (1024 * 4));
263 			hexdump(ptr, framelen);
264 			ptr += framelen;
265 		}
266 	}
267 	if (verbose >= 2) {
268 		print_flags(up->up_flags);
269 		print_status(up->up_status);
270 	}
271 }
272 
273 static void
274 print_packets(char *data, const int datalen)
275 {
276 	struct usbpf_pkthdr *up;
277 	const struct bpf_xhdr *hdr;
278 	u_int32_t framelen, x;
279 	char *ptr, *next;
280 
281 	for (ptr = data; ptr < (data + datalen); ptr = next) {
282 		hdr = (const struct bpf_xhdr *)ptr;
283 		up = (struct usbpf_pkthdr *)(ptr + hdr->bh_hdrlen);
284 		next = ptr + BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
285 
286 		ptr = ((char *)up) + sizeof(struct usbpf_pkthdr);
287 		if (w_arg == NULL)
288 			print_apacket(hdr, up, ptr);
289 		pkt_captured++;
290 		for (x = 0; x < up->up_frames; x++) {
291 			framelen = le32toh(*((const u_int32_t *)ptr));
292 			ptr += sizeof(u_int32_t) + framelen;
293 		}
294 	}
295 }
296 
297 static void
298 write_packets(struct usbcap *p, const char *data, const int datalen)
299 {
300 	int len = htole32(datalen), ret;
301 
302 	ret = write(p->wfd, &len, sizeof(int));
303 	assert(ret == sizeof(int));
304 	ret = write(p->wfd, data, datalen);
305 	assert(ret == datalen);
306 }
307 
308 static void
309 read_file(struct usbcap *p)
310 {
311 	int datalen, ret;
312 	char *data;
313 
314 	while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) {
315 		datalen = le32toh(datalen);
316 		data = malloc(datalen);
317 		assert(data != NULL);
318 		ret = read(p->rfd, data, datalen);
319 		assert(ret == datalen);
320 		print_packets(data, datalen);
321 		free(data);
322 	}
323 	if (ret == -1)
324 		fprintf(stderr, "read: %s\n", strerror(errno));
325 }
326 
327 static void
328 do_loop(struct usbcap *p)
329 {
330 	int cc;
331 
332 	while (doexit == 0) {
333 		cc = read(p->fd, (char *)p->buffer, p->bufsize);
334 		if (cc < 0) {
335 			switch (errno) {
336 			case EINTR:
337 				break;
338 			default:
339 				fprintf(stderr, "read: %s\n", strerror(errno));
340 				return;
341 			}
342 			continue;
343 		}
344 		if (cc == 0)
345 			continue;
346 		if (w_arg != NULL)
347 			write_packets(p, p->buffer, cc);
348 		print_packets(p->buffer, cc);
349 	}
350 }
351 
352 static void
353 init_rfile(struct usbcap *p)
354 {
355 	struct usbcap_filehdr uf;
356 	int ret;
357 
358 	p->rfd = open(r_arg, O_RDONLY);
359 	if (p->rfd < 0) {
360 		fprintf(stderr, "open: %s (%s)\n", r_arg, strerror(errno));
361 		exit(EXIT_FAILURE);
362 	}
363 	ret = read(p->rfd, &uf, sizeof(uf));
364 	assert(ret == sizeof(uf));
365 	assert(le32toh(uf.magic) == USBCAP_FILEHDR_MAGIC);
366 	assert(uf.major == 0);
367 	assert(uf.minor == 1);
368 }
369 
370 static void
371 init_wfile(struct usbcap *p)
372 {
373 	struct usbcap_filehdr uf;
374 	int ret;
375 
376 	p->wfd = open(w_arg, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
377 	if (p->wfd < 0) {
378 		fprintf(stderr, "open: %s (%s)\n", w_arg, strerror(errno));
379 		exit(EXIT_FAILURE);
380 	}
381 	bzero(&uf, sizeof(uf));
382 	uf.magic = htole32(USBCAP_FILEHDR_MAGIC);
383 	uf.major = 0;
384 	uf.minor = 1;
385 	ret = write(p->wfd, (const void *)&uf, sizeof(uf));
386 	assert(ret == sizeof(uf));
387 }
388 
389 static void
390 usage(void)
391 {
392 
393 #define FMT "    %-14s %s\n"
394 	fprintf(stderr, "usage: usbdump [options]\n");
395 	fprintf(stderr, FMT, "-i ifname", "Listen on USB bus interface");
396 	fprintf(stderr, FMT, "-r file", "Read the raw packets from file");
397 	fprintf(stderr, FMT, "-s snaplen", "Snapshot bytes from each packet");
398 	fprintf(stderr, FMT, "-v", "Increases the verbose level");
399 	fprintf(stderr, FMT, "-w file", "Write the raw packets to file");
400 #undef FMT
401 	exit(1);
402 }
403 
404 int
405 main(int argc, char *argv[])
406 {
407 	struct timeval tv;
408 	struct bpf_insn total_insn;
409 	struct bpf_program total_prog;
410 	struct bpf_stat us;
411 	struct bpf_version bv;
412 	struct usbcap uc, *p = &uc;
413 	struct ifreq ifr;
414 	long snapshot = 192;
415 	u_int v;
416 	int fd, o;
417 	const char *optstring;
418 
419 	bzero(&uc, sizeof(struct usbcap));
420 
421 	optstring = "i:r:s:vw:";
422 	while ((o = getopt(argc, argv, optstring)) != -1) {
423 		switch (o) {
424 		case 'i':
425 			i_arg = optarg;
426 			break;
427 		case 'r':
428 			r_arg = optarg;
429 			init_rfile(p);
430 			break;
431 		case 's':
432 			snapshot = strtol(optarg, NULL, 10);
433 			errno = 0;
434 			if (snapshot == 0 && errno == EINVAL)
435 				usage();
436 			/* snapeshot == 0 is special */
437 			if (snapshot == 0)
438 				snapshot = -1;
439 			break;
440 		case 'v':
441 			verbose++;
442 			break;
443 		case 'w':
444 			w_arg = optarg;
445 			init_wfile(p);
446 			break;
447 		default:
448 			usage();
449 			/* NOTREACHED */
450 		}
451 	}
452 
453 	if (r_arg != NULL) {
454 		read_file(p);
455 		exit(EXIT_SUCCESS);
456 	}
457 
458 	p->fd = fd = open("/dev/bpf", O_RDONLY);
459 	if (p->fd < 0) {
460 		fprintf(stderr, "(no devices found)\n");
461 		return (EXIT_FAILURE);
462 	}
463 
464 	if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
465 		fprintf(stderr, "BIOCVERSION: %s\n", strerror(errno));
466 		return (EXIT_FAILURE);
467 	}
468 	if (bv.bv_major != BPF_MAJOR_VERSION ||
469 	    bv.bv_minor < BPF_MINOR_VERSION) {
470 		fprintf(stderr, "kernel bpf filter out of date");
471 		return (EXIT_FAILURE);
472 	}
473 
474 	if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < 4096)
475 		v = 4096;
476 	for ( ; v != 0; v >>= 1) {
477 		(void)ioctl(fd, BIOCSBLEN, (caddr_t)&v);
478 		(void)strncpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name));
479 		if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
480 			break;
481 	}
482 	if (v == 0) {
483 		fprintf(stderr, "BIOCSBLEN: %s: No buffer size worked", i_arg);
484 		return (EXIT_FAILURE);
485 	}
486 
487 	if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
488 		fprintf(stderr, "BIOCGBLEN: %s", strerror(errno));
489 		return (EXIT_FAILURE);
490 	}
491 
492 	p->bufsize = v;
493 	p->buffer = (u_char *)malloc(p->bufsize);
494 	if (p->buffer == NULL) {
495 		fprintf(stderr, "malloc: %s", strerror(errno));
496 		return (EXIT_FAILURE);
497 	}
498 
499 	/* XXX no read filter rules yet so at this moment accept everything */
500 	total_insn.code = (u_short)(BPF_RET | BPF_K);
501 	total_insn.jt = 0;
502 	total_insn.jf = 0;
503 	total_insn.k = snapshot;
504 
505 	total_prog.bf_len = 1;
506 	total_prog.bf_insns = &total_insn;
507 	if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) {
508 		fprintf(stderr, "BIOCSETF: %s", strerror(errno));
509 		return (EXIT_FAILURE);
510 	}
511 
512 	/* 1 second read timeout */
513 	tv.tv_sec = 1;
514 	tv.tv_usec = 0;
515 	if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&tv) < 0) {
516 		fprintf(stderr, "BIOCSRTIMEOUT: %s", strerror(errno));
517 		return (EXIT_FAILURE);
518 	}
519 
520 	(void)signal(SIGINT, handle_sigint);
521 
522 	do_loop(p);
523 
524 	if (ioctl(fd, BIOCGSTATS, (caddr_t)&us) < 0) {
525 		fprintf(stderr, "BIOCGSTATS: %s", strerror(errno));
526 		return (EXIT_FAILURE);
527 	}
528 
529 	/* XXX what's difference between pkt_captured and us.us_recv? */
530 	printf("\n");
531 	printf("%d packets captured\n", pkt_captured);
532 	printf("%d packets received by filter\n", us.bs_recv);
533 	printf("%d packets dropped by kernel\n", us.bs_drop);
534 
535 	if (p->fd > 0)
536 		close(p->fd);
537 	if (p->rfd > 0)
538 		close(p->rfd);
539 	if (p->wfd > 0)
540 		close(p->wfd);
541 
542 	return (EXIT_SUCCESS);
543 }
544