1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010 Weongyo Jeong <weongyo@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer,
12 *    without modification.
13 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
15 *    redistribution must be conditioned upon including a substantially
16 *    similar Disclaimer requirement for further binary redistribution.
17 *
18 * NO WARRANTY
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
22 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
24 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29 * THE POSSIBILITY OF SUCH DAMAGES.
30 *
31 * $FreeBSD: stable/11/usr.sbin/usbdump/usbdump.c 349665 2019-07-03 18:18:42Z hselasky $
32 */
33
34#include <sys/param.h>
35#include <sys/endian.h>
36#include <sys/ioctl.h>
37#include <sys/socket.h>
38#include <sys/stat.h>
39#include <sys/sysctl.h>
40#include <sys/utsname.h>
41#include <sys/queue.h>
42#include <net/if.h>
43#include <net/bpf.h>
44#include <dev/usb/usb.h>
45#include <dev/usb/usb_pf.h>
46#include <dev/usb/usbdi.h>
47#include <errno.h>
48#include <fcntl.h>
49#include <limits.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <stdint.h>
53#include <string.h>
54#include <time.h>
55#include <unistd.h>
56#include <sysexits.h>
57#include <err.h>
58
59#define	BPF_STORE_JUMP(x,_c,_k,_jt,_jf) do {	\
60  (x).code = (_c);				\
61  (x).k = (_k);					\
62  (x).jt = (_jt);				\
63  (x).jf = (_jf);				\
64} while (0)
65
66#define	BPF_STORE_STMT(x,_c,_k) do {		\
67  (x).code = (_c);				\
68  (x).k = (_k);					\
69  (x).jt = 0;					\
70  (x).jf = 0;					\
71} while (0)
72
73struct usb_filt {
74	STAILQ_ENTRY(usb_filt) entry;
75	int unit;
76	int endpoint;
77};
78
79struct usbcap {
80	int		fd;		/* fd for /dev/usbpf */
81	uint32_t	bufsize;
82	uint8_t		*buffer;
83
84	/* for -w option */
85	int		wfd;
86	/* for -r option */
87	int		rfd;
88	/* for -b option */
89	int		bfd;
90};
91
92struct usbcap_filehdr {
93	uint32_t	magic;
94#define	USBCAP_FILEHDR_MAGIC	0x9a90000e
95	uint8_t   	major;
96	uint8_t		minor;
97	uint8_t		reserved[26];
98} __packed;
99
100struct header_32 {
101	/* capture timestamp */
102	uint32_t ts_sec;
103	uint32_t ts_usec;
104	/* data length and alignment information */
105	uint32_t caplen;
106	uint32_t datalen;
107	uint8_t hdrlen;
108	uint8_t align;
109} __packed;
110
111static int doexit = 0;
112static int pkt_captured = 0;
113static int verbose = 0;
114static int uf_minor;
115static const char *i_arg = "usbus0";
116static const char *r_arg = NULL;
117static const char *w_arg = NULL;
118static const char *b_arg = NULL;
119static struct usbcap uc;
120static const char *errstr_table[USB_ERR_MAX] = {
121	[USB_ERR_NORMAL_COMPLETION]	= "0",
122	[USB_ERR_PENDING_REQUESTS]	= "PENDING_REQUESTS",
123	[USB_ERR_NOT_STARTED]		= "NOT_STARTED",
124	[USB_ERR_INVAL]			= "INVAL",
125	[USB_ERR_NOMEM]			= "NOMEM",
126	[USB_ERR_CANCELLED]		= "CANCELLED",
127	[USB_ERR_BAD_ADDRESS]		= "BAD_ADDRESS",
128	[USB_ERR_BAD_BUFSIZE]		= "BAD_BUFSIZE",
129	[USB_ERR_BAD_FLAG]		= "BAD_FLAG",
130	[USB_ERR_NO_CALLBACK]		= "NO_CALLBACK",
131	[USB_ERR_IN_USE]		= "IN_USE",
132	[USB_ERR_NO_ADDR]		= "NO_ADDR",
133	[USB_ERR_NO_PIPE]		= "NO_PIPE",
134	[USB_ERR_ZERO_NFRAMES]		= "ZERO_NFRAMES",
135	[USB_ERR_ZERO_MAXP]		= "ZERO_MAXP",
136	[USB_ERR_SET_ADDR_FAILED]	= "SET_ADDR_FAILED",
137	[USB_ERR_NO_POWER]		= "NO_POWER",
138	[USB_ERR_TOO_DEEP]		= "TOO_DEEP",
139	[USB_ERR_IOERROR]		= "IOERROR",
140	[USB_ERR_NOT_CONFIGURED]	= "NOT_CONFIGURED",
141	[USB_ERR_TIMEOUT]		= "TIMEOUT",
142	[USB_ERR_SHORT_XFER]		= "SHORT_XFER",
143	[USB_ERR_STALLED]		= "STALLED",
144	[USB_ERR_INTERRUPTED]		= "INTERRUPTED",
145	[USB_ERR_DMA_LOAD_FAILED]	= "DMA_LOAD_FAILED",
146	[USB_ERR_BAD_CONTEXT]		= "BAD_CONTEXT",
147	[USB_ERR_NO_ROOT_HUB]		= "NO_ROOT_HUB",
148	[USB_ERR_NO_INTR_THREAD]	= "NO_INTR_THREAD",
149	[USB_ERR_NOT_LOCKED]		= "NOT_LOCKED",
150};
151
152#define	USB_XFERTYPE_MAX 4
153
154static const char *xfertype_table[USB_XFERTYPE_MAX] = {
155	[UE_CONTROL]			= "CTRL",
156	[UE_ISOCHRONOUS]		= "ISOC",
157	[UE_BULK]			= "BULK",
158	[UE_INTERRUPT]			= "INTR"
159};
160
161static const char *speed_table[USB_SPEED_MAX] = {
162	[USB_SPEED_FULL] = "FULL",
163	[USB_SPEED_HIGH] = "HIGH",
164	[USB_SPEED_LOW] = "LOW",
165	[USB_SPEED_VARIABLE] = "VARI",
166	[USB_SPEED_SUPER] = "SUPER",
167};
168
169static STAILQ_HEAD(,usb_filt) usb_filt_head =
170    STAILQ_HEAD_INITIALIZER(usb_filt_head);
171
172static void
173add_filter(int usb_filt_unit, int usb_filt_ep)
174{
175	struct usb_filt *puf;
176
177	puf = malloc(sizeof(struct usb_filt));
178	if (puf == NULL)
179		errx(EX_SOFTWARE, "Out of memory.");
180
181	puf->unit = usb_filt_unit;
182	puf->endpoint = usb_filt_ep;
183
184	STAILQ_INSERT_TAIL(&usb_filt_head, puf, entry);
185}
186
187static void
188make_filter(struct bpf_program *pprog, int snapshot)
189{
190	struct usb_filt *puf;
191	struct bpf_insn *dynamic_insn;
192	int len;
193
194	len = 0;
195
196	STAILQ_FOREACH(puf, &usb_filt_head, entry)
197		len++;
198
199	dynamic_insn = malloc(((len * 5) + 1) * sizeof(struct bpf_insn));
200
201	if (dynamic_insn == NULL)
202		errx(EX_SOFTWARE, "Out of memory.");
203
204	len++;
205
206	if (len == 1) {
207		/* accept all packets */
208
209		BPF_STORE_STMT(dynamic_insn[0], BPF_RET | BPF_K, snapshot);
210
211		goto done;
212	}
213
214	len = 0;
215
216	STAILQ_FOREACH(puf, &usb_filt_head, entry) {
217		const int addr_off = (uintptr_t)&((struct usbpf_pkthdr *)0)->up_address;
218		const int addr_ep = (uintptr_t)&((struct usbpf_pkthdr *)0)->up_endpoint;
219
220		if (puf->unit != -1) {
221			if (puf->endpoint != -1) {
222				BPF_STORE_STMT(dynamic_insn[len],
223				    BPF_LD | BPF_B | BPF_ABS, addr_off);
224				len++;
225				BPF_STORE_JUMP(dynamic_insn[len],
226				    BPF_JMP | BPF_JEQ | BPF_K, (uint8_t)puf->unit, 0, 3);
227				len++;
228				BPF_STORE_STMT(dynamic_insn[len],
229				    BPF_LD | BPF_W | BPF_ABS, addr_ep);
230				len++;
231				BPF_STORE_JUMP(dynamic_insn[len],
232				    BPF_JMP | BPF_JEQ | BPF_K, htobe32(puf->endpoint), 0, 1);
233				len++;
234			} else {
235				BPF_STORE_STMT(dynamic_insn[len],
236				    BPF_LD | BPF_B | BPF_ABS, addr_off);
237				len++;
238				BPF_STORE_JUMP(dynamic_insn[len],
239				    BPF_JMP | BPF_JEQ | BPF_K, (uint8_t)puf->unit, 0, 1);
240				len++;
241			}
242		} else {
243			if (puf->endpoint != -1) {
244				BPF_STORE_STMT(dynamic_insn[len],
245				    BPF_LD | BPF_W | BPF_ABS, addr_ep);
246				len++;
247				BPF_STORE_JUMP(dynamic_insn[len],
248				    BPF_JMP | BPF_JEQ | BPF_K, htobe32(puf->endpoint), 0, 1);
249				len++;
250			}
251		}
252		BPF_STORE_STMT(dynamic_insn[len],
253		    BPF_RET | BPF_K, snapshot);
254		len++;
255	}
256
257	BPF_STORE_STMT(dynamic_insn[len], BPF_RET | BPF_K, 0);
258	len++;
259
260done:
261	pprog->bf_len = len;
262	pprog->bf_insns = dynamic_insn;
263}
264
265static int
266match_filter(int unit, int endpoint)
267{
268	struct usb_filt *puf;
269
270	if (STAILQ_FIRST(&usb_filt_head) == NULL)
271		return (1);
272
273	STAILQ_FOREACH(puf, &usb_filt_head, entry) {
274		if ((puf->unit == -1 || puf->unit == unit) &&
275		    (puf->endpoint == -1 || puf->endpoint == endpoint))
276			return (1);
277	}
278	return (0);
279}
280
281static void
282free_filter(struct bpf_program *pprog)
283{
284	struct usb_filt *puf;
285
286	while ((puf = STAILQ_FIRST(&usb_filt_head)) != NULL) {
287		STAILQ_REMOVE_HEAD(&usb_filt_head, entry);
288		free(puf);
289	}
290	free(pprog->bf_insns);
291}
292
293static void
294handle_sigint(int sig)
295{
296
297	(void)sig;
298	doexit = 1;
299}
300
301#define	FLAGS(x, name)	\
302	(((x) & USBPF_FLAG_##name) ? #name "|" : "")
303
304#define	STATUS(x, name) \
305	(((x) & USBPF_STATUS_##name) ? #name "|" : "")
306
307static const char *
308usb_errstr(uint32_t error)
309{
310	if (error >= USB_ERR_MAX || errstr_table[error] == NULL)
311		return ("UNKNOWN");
312	else
313		return (errstr_table[error]);
314}
315
316static const char *
317usb_speedstr(uint8_t speed)
318{
319	if (speed >= USB_SPEED_MAX  || speed_table[speed] == NULL)
320		return ("UNKNOWN");
321	else
322		return (speed_table[speed]);
323}
324
325static const char *
326usb_xferstr(uint8_t type)
327{
328	if (type >= USB_XFERTYPE_MAX  || xfertype_table[type] == NULL)
329		return ("UNKN");
330	else
331		return (xfertype_table[type]);
332}
333
334static void
335print_flags(uint32_t flags)
336{
337	printf(" flags %#x <%s%s%s%s%s%s%s%s%s0>\n",
338	    flags,
339	    FLAGS(flags, FORCE_SHORT_XFER),
340	    FLAGS(flags, SHORT_XFER_OK),
341	    FLAGS(flags, SHORT_FRAMES_OK),
342	    FLAGS(flags, PIPE_BOF),
343	    FLAGS(flags, PROXY_BUFFER),
344	    FLAGS(flags, EXT_BUFFER),
345	    FLAGS(flags, MANUAL_STATUS),
346	    FLAGS(flags, NO_PIPE_OK),
347	    FLAGS(flags, STALL_PIPE));
348}
349
350static void
351print_status(uint32_t status)
352{
353	printf(" status %#x <%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s0>\n",
354	    status,
355	    STATUS(status, OPEN),
356	    STATUS(status, TRANSFERRING),
357	    STATUS(status, DID_DMA_DELAY),
358	    STATUS(status, DID_CLOSE),
359	    STATUS(status, DRAINING),
360	    STATUS(status, STARTED),
361	    STATUS(status, BW_RECLAIMED),
362	    STATUS(status, CONTROL_XFR),
363	    STATUS(status, CONTROL_HDR),
364	    STATUS(status, CONTROL_ACT),
365	    STATUS(status, CONTROL_STALL),
366	    STATUS(status, SHORT_FRAMES_OK),
367	    STATUS(status, SHORT_XFER_OK),
368	    STATUS(status, BDMA_ENABLE),
369	    STATUS(status, BDMA_NO_POST_SYNC),
370	    STATUS(status, BDMA_SETUP),
371	    STATUS(status, ISOCHRONOUS_XFR),
372	    STATUS(status, CURR_DMA_SET),
373	    STATUS(status, CAN_CANCEL_IMMED),
374	    STATUS(status, DOING_CALLBACK));
375}
376
377/*
378 * Dump a byte into hex format.
379 */
380static void
381hexbyte(char *buf, uint8_t temp)
382{
383	uint8_t lo;
384	uint8_t hi;
385
386	lo = temp & 0xF;
387	hi = temp >> 4;
388
389	if (hi < 10)
390		buf[0] = '0' + hi;
391	else
392		buf[0] = 'A' + hi - 10;
393
394	if (lo < 10)
395		buf[1] = '0' + lo;
396	else
397		buf[1] = 'A' + lo - 10;
398}
399
400/*
401 * Display a region in traditional hexdump format.
402 */
403static void
404hexdump(const uint8_t *region, uint32_t len)
405{
406	const uint8_t *line;
407	char linebuf[128];
408	int i;
409	int x;
410	int c;
411
412	for (line = region; line < (region + len); line += 16) {
413
414		i = 0;
415
416		linebuf[i] = ' ';
417		hexbyte(linebuf + i + 1, ((line - region) >> 8) & 0xFF);
418		hexbyte(linebuf + i + 3, (line - region) & 0xFF);
419		linebuf[i + 5] = ' ';
420		linebuf[i + 6] = ' ';
421		i += 7;
422
423		for (x = 0; x < 16; x++) {
424		  if ((line + x) < (region + len)) {
425			hexbyte(linebuf + i,
426			    *(const u_int8_t *)(line + x));
427		  } else {
428			  linebuf[i] = '-';
429			  linebuf[i + 1] = '-';
430			}
431			linebuf[i + 2] = ' ';
432			if (x == 7) {
433			  linebuf[i + 3] = ' ';
434			  i += 4;
435			} else {
436			  i += 3;
437			}
438		}
439		linebuf[i] = ' ';
440		linebuf[i + 1] = '|';
441		i += 2;
442		for (x = 0; x < 16; x++) {
443			if ((line + x) < (region + len)) {
444				c = *(const u_int8_t *)(line + x);
445				/* !isprint(c) */
446				if ((c < ' ') || (c > '~'))
447					c = '.';
448				linebuf[i] = c;
449			} else {
450				linebuf[i] = ' ';
451			}
452			i++;
453		}
454		linebuf[i] = '|';
455		linebuf[i + 1] = 0;
456		i += 2;
457		puts(linebuf);
458	}
459}
460
461static void
462print_apacket(const struct header_32 *hdr, const uint8_t *ptr, int ptr_len)
463{
464	struct tm *tm;
465	struct usbpf_pkthdr up_temp;
466	struct usbpf_pkthdr *up;
467	struct timeval tv;
468	size_t len;
469	uint32_t x;
470	char buf[64];
471
472	ptr += USBPF_HDR_LEN;
473	ptr_len -= USBPF_HDR_LEN;
474	if (ptr_len < 0)
475		return;
476
477	/* make sure we don't change the source buffer */
478	memcpy(&up_temp, ptr - USBPF_HDR_LEN, sizeof(up_temp));
479	up = &up_temp;
480
481	/*
482	 * A packet from the kernel is based on little endian byte
483	 * order.
484	 */
485	up->up_totlen = le32toh(up->up_totlen);
486	up->up_busunit = le32toh(up->up_busunit);
487	up->up_flags = le32toh(up->up_flags);
488	up->up_status = le32toh(up->up_status);
489	up->up_error = le32toh(up->up_error);
490	up->up_interval = le32toh(up->up_interval);
491	up->up_frames = le32toh(up->up_frames);
492	up->up_packet_size = le32toh(up->up_packet_size);
493	up->up_packet_count = le32toh(up->up_packet_count);
494	up->up_endpoint = le32toh(up->up_endpoint);
495
496	if (!match_filter(up->up_address, up->up_endpoint))
497		return;
498
499	tv.tv_sec = hdr->ts_sec;
500	tv.tv_usec = hdr->ts_usec;
501	tm = localtime(&tv.tv_sec);
502
503	len = strftime(buf, sizeof(buf), "%H:%M:%S", tm);
504
505	if (verbose >= 0) {
506		printf("%.*s.%06ld usbus%d.%d %s-%s-EP=%08x,SPD=%s,NFR=%d,SLEN=%d,IVAL=%d%s%s\n",
507		    (int)len, buf, tv.tv_usec,
508		    (int)up->up_busunit, (int)up->up_address,
509		    (up->up_type == USBPF_XFERTAP_SUBMIT) ? "SUBM" : "DONE",
510		    usb_xferstr(up->up_xfertype),
511		    (unsigned int)up->up_endpoint,
512		    usb_speedstr(up->up_speed),
513		    (int)up->up_frames,
514		    (int)(up->up_totlen - USBPF_HDR_LEN -
515		    (USBPF_FRAME_HDR_LEN * up->up_frames)),
516		    (int)up->up_interval,
517		    (up->up_type == USBPF_XFERTAP_DONE) ? ",ERR=" : "",
518		    (up->up_type == USBPF_XFERTAP_DONE) ?
519		    usb_errstr(up->up_error) : "");
520	}
521
522	if (verbose >= 1 || b_arg != NULL) {
523		for (x = 0; x != up->up_frames; x++) {
524			const struct usbpf_framehdr *uf;
525			uint32_t framelen;
526			uint32_t flags;
527
528			uf = (const struct usbpf_framehdr *)ptr;
529			ptr += USBPF_FRAME_HDR_LEN;
530			ptr_len -= USBPF_FRAME_HDR_LEN;
531			if (ptr_len < 0)
532				return;
533
534			framelen = le32toh(uf->length);
535			flags = le32toh(uf->flags);
536
537			if (verbose >= 1) {
538				printf(" frame[%u] %s %d bytes\n",
539				    (unsigned int)x,
540				    (flags & USBPF_FRAMEFLAG_READ) ? "READ" : "WRITE",
541				    (int)framelen);
542			}
543
544			if (flags & USBPF_FRAMEFLAG_DATA_FOLLOWS) {
545
546				int tot_frame_len;
547
548				tot_frame_len = USBPF_FRAME_ALIGN(framelen);
549
550				ptr_len -= tot_frame_len;
551
552				if (tot_frame_len < 0 ||
553				    (int)framelen < 0 || (int)ptr_len < 0)
554					break;
555
556				if (b_arg != NULL) {
557					struct usbcap *p = &uc;
558					int ret;
559					ret = write(p->bfd, ptr, framelen);
560					if (ret != (int)framelen)
561						err(EXIT_FAILURE, "Could not write binary data");
562				}
563				if (verbose >= 1)
564					hexdump(ptr, framelen);
565
566				ptr += tot_frame_len;
567			}
568		}
569	}
570	if (verbose >= 2)
571		print_flags(up->up_flags);
572	if (verbose >= 3)
573		print_status(up->up_status);
574}
575
576static void
577fix_packets(uint8_t *data, const int datalen)
578{
579	struct header_32 temp;
580	uint8_t *ptr;
581	uint8_t *next;
582	uint32_t hdrlen;
583	uint32_t caplen;
584
585	for (ptr = data; ptr < (data + datalen); ptr = next) {
586
587		const struct bpf_hdr *hdr;
588
589		hdr = (const struct bpf_hdr *)ptr;
590
591		temp.ts_sec = htole32(hdr->bh_tstamp.tv_sec);
592		temp.ts_usec = htole32(hdr->bh_tstamp.tv_usec);
593		temp.caplen = htole32(hdr->bh_caplen);
594		temp.datalen = htole32(hdr->bh_datalen);
595		temp.hdrlen = hdr->bh_hdrlen;
596		temp.align = BPF_WORDALIGN(1);
597
598		hdrlen = hdr->bh_hdrlen;
599		caplen = hdr->bh_caplen;
600
601		if ((hdrlen >= sizeof(temp)) && (hdrlen <= 255) &&
602		    ((ptr + hdrlen) <= (data + datalen))) {
603			memcpy(ptr, &temp, sizeof(temp));
604			memset(ptr + sizeof(temp), 0, hdrlen - sizeof(temp));
605		} else {
606			err(EXIT_FAILURE, "Invalid header length %d", hdrlen);
607		}
608
609		next = ptr + BPF_WORDALIGN(hdrlen + caplen);
610
611		if (next <= ptr)
612			err(EXIT_FAILURE, "Invalid length");
613	}
614}
615
616static void
617print_packets(uint8_t *data, const int datalen)
618{
619	struct header_32 temp;
620	uint8_t *ptr;
621	uint8_t *next;
622
623	for (ptr = data; ptr < (data + datalen); ptr = next) {
624
625		const struct header_32 *hdr32;
626
627		hdr32 = (const struct header_32 *)ptr;
628
629		temp.ts_sec = le32toh(hdr32->ts_sec);
630		temp.ts_usec = le32toh(hdr32->ts_usec);
631		temp.caplen = le32toh(hdr32->caplen);
632		temp.datalen = le32toh(hdr32->datalen);
633		temp.hdrlen = hdr32->hdrlen;
634		temp.align = hdr32->align;
635
636		next = ptr + roundup2(temp.hdrlen + temp.caplen, temp.align);
637
638		if (next <= ptr)
639			err(EXIT_FAILURE, "Invalid length");
640
641		if (verbose >= 0 || r_arg != NULL || b_arg != NULL) {
642			print_apacket(&temp, ptr +
643			    temp.hdrlen, temp.caplen);
644		}
645		pkt_captured++;
646	}
647}
648
649static void
650write_packets(struct usbcap *p, const uint8_t *data, const int datalen)
651{
652	int len = htole32(datalen);
653	int ret;
654
655	ret = write(p->wfd, &len, sizeof(int));
656	if (ret != sizeof(int)) {
657		err(EXIT_FAILURE, "Could not write length "
658		    "field of USB data payload");
659	}
660	ret = write(p->wfd, data, datalen);
661	if (ret != datalen) {
662		err(EXIT_FAILURE, "Could not write "
663		    "complete USB data payload");
664	}
665}
666
667static void
668read_file(struct usbcap *p)
669{
670	int datalen;
671	int ret;
672	uint8_t *data;
673
674	while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) {
675		datalen = le32toh(datalen);
676		data = malloc(datalen);
677		if (data == NULL)
678			errx(EX_SOFTWARE, "Out of memory.");
679		ret = read(p->rfd, data, datalen);
680		if (ret != datalen) {
681			err(EXIT_FAILURE, "Could not read complete "
682			    "USB data payload");
683		}
684		if (uf_minor == 2)
685			fix_packets(data, datalen);
686
687		print_packets(data, datalen);
688		free(data);
689	}
690}
691
692static void
693do_loop(struct usbcap *p)
694{
695	int cc;
696
697	while (doexit == 0) {
698		cc = read(p->fd, (uint8_t *)p->buffer, p->bufsize);
699		if (cc < 0) {
700			switch (errno) {
701			case EINTR:
702				break;
703			default:
704				fprintf(stderr, "read: %s\n", strerror(errno));
705				return;
706			}
707			continue;
708		}
709		if (cc == 0)
710			continue;
711
712		fix_packets(p->buffer, cc);
713
714		if (w_arg != NULL)
715			write_packets(p, p->buffer, cc);
716		print_packets(p->buffer, cc);
717	}
718}
719
720static void
721init_rfile(struct usbcap *p)
722{
723	struct usbcap_filehdr uf;
724	int ret;
725
726	p->rfd = open(r_arg, O_RDONLY);
727	if (p->rfd < 0) {
728		err(EXIT_FAILURE, "Could not open "
729		    "'%s' for read", r_arg);
730	}
731	ret = read(p->rfd, &uf, sizeof(uf));
732	if (ret != sizeof(uf)) {
733		err(EXIT_FAILURE, "Could not read USB capture "
734		    "file header");
735	}
736	if (le32toh(uf.magic) != USBCAP_FILEHDR_MAGIC) {
737		errx(EX_SOFTWARE, "Invalid magic field(0x%08x) "
738		    "in USB capture file header.",
739		    (unsigned int)le32toh(uf.magic));
740	}
741	if (uf.major != 0) {
742		errx(EX_SOFTWARE, "Invalid major version(%d) "
743		    "field in USB capture file header.", (int)uf.major);
744	}
745
746	uf_minor = uf.minor;
747
748	if (uf.minor != 3 && uf.minor != 2) {
749		errx(EX_SOFTWARE, "Invalid minor version(%d) "
750		    "field in USB capture file header.", (int)uf.minor);
751	}
752}
753
754static void
755init_wfile(struct usbcap *p)
756{
757	struct usbcap_filehdr uf;
758	int ret;
759
760	p->wfd = open(w_arg, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
761	if (p->wfd < 0) {
762		err(EXIT_FAILURE, "Could not open "
763		    "'%s' for write", w_arg);
764	}
765	memset(&uf, 0, sizeof(uf));
766	uf.magic = htole32(USBCAP_FILEHDR_MAGIC);
767	uf.major = 0;
768	uf.minor = 3;
769	ret = write(p->wfd, (const void *)&uf, sizeof(uf));
770	if (ret != sizeof(uf)) {
771		err(EXIT_FAILURE, "Could not write "
772		    "USB capture header");
773	}
774}
775
776static void
777usage(void)
778{
779
780#define FMT "    %-14s %s\n"
781	fprintf(stderr, "usage: usbdump [options]\n");
782	fprintf(stderr, FMT, "-i <usbusX>", "Listen on USB bus interface");
783	fprintf(stderr, FMT, "-f <unit[.endpoint]>", "Specify a device and endpoint filter");
784	fprintf(stderr, FMT, "-r <file>", "Read the raw packets from file");
785	fprintf(stderr, FMT, "-s <snaplen>", "Snapshot bytes from each packet");
786	fprintf(stderr, FMT, "-v", "Increase the verbose level");
787	fprintf(stderr, FMT, "-b <file>", "Save raw version of all recorded data to file");
788	fprintf(stderr, FMT, "-w <file>", "Write the raw packets to file");
789	fprintf(stderr, FMT, "-h", "Display summary of command line options");
790#undef FMT
791	exit(EX_USAGE);
792}
793
794static void
795check_usb_pf_sysctl(void)
796{
797	int error;
798	int no_pf_val = 0;
799	size_t no_pf_len = sizeof(int);
800
801	/* check "hw.usb.no_pf" sysctl for 8- and 9- stable */
802
803	error = sysctlbyname("hw.usb.no_pf", &no_pf_val,
804	    &no_pf_len, NULL, 0);
805	if (error == 0 && no_pf_val != 0) {
806		warnx("The USB packet filter might be disabled.");
807		warnx("See the \"hw.usb.no_pf\" sysctl for more information.");
808	}
809}
810
811int
812main(int argc, char *argv[])
813{
814	struct timeval tv;
815	struct bpf_program total_prog;
816	struct bpf_stat us;
817	struct bpf_version bv;
818	struct usbcap *p = &uc;
819	struct ifreq ifr;
820	long snapshot = 192;
821	uint32_t v;
822	int fd;
823	int o;
824	int filt_unit;
825	int filt_ep;
826	int s;
827	int ifindex;
828	const char *optstring;
829	char *pp;
830
831	optstring = "b:hi:r:s:vw:f:";
832	while ((o = getopt(argc, argv, optstring)) != -1) {
833		switch (o) {
834		case 'i':
835			i_arg = optarg;
836			break;
837		case 'r':
838			r_arg = optarg;
839			init_rfile(p);
840			break;
841		case 's':
842			snapshot = strtol(optarg, &pp, 10);
843			errno = 0;
844			if (pp != NULL && *pp != 0)
845				usage();
846			if (snapshot == 0 && errno == EINVAL)
847				usage();
848			/* snapeshot == 0 is special */
849			if (snapshot == 0)
850				snapshot = -1;
851			break;
852		case 'b':
853			b_arg = optarg;
854			break;
855		case 'v':
856			verbose++;
857			break;
858		case 'w':
859			w_arg = optarg;
860			init_wfile(p);
861			break;
862		case 'f':
863			filt_unit = strtol(optarg, &pp, 10);
864			filt_ep = -1;
865			if (pp != NULL) {
866				if (*pp == '.') {
867					filt_ep = strtol(pp + 1, &pp, 10);
868					if (pp != NULL && *pp != 0)
869						usage();
870				} else if (*pp != 0) {
871					usage();
872				}
873			}
874			add_filter(filt_unit, filt_ep);
875			break;
876		default:
877			usage();
878			/* NOTREACHED */
879		}
880	}
881
882	if (b_arg != NULL) {
883		p->bfd = open(b_arg, O_CREAT | O_TRUNC |
884		    O_WRONLY, S_IRUSR | S_IWUSR);
885		if (p->bfd < 0) {
886			err(EXIT_FAILURE, "Could not open "
887			    "'%s' for write", b_arg);
888		}
889	}
890
891	/*
892	 * Require more verbosity to print anything when -w or -b is
893	 * specified on the command line:
894	 */
895	if (w_arg != NULL || b_arg != NULL)
896		verbose--;
897
898	if (r_arg != NULL) {
899		read_file(p);
900		exit(EXIT_SUCCESS);
901	}
902
903	check_usb_pf_sysctl();
904
905	p->fd = fd = open("/dev/bpf", O_RDONLY);
906	if (p->fd < 0)
907		err(EXIT_FAILURE, "Could not open BPF device");
908
909	if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0)
910		err(EXIT_FAILURE, "BIOCVERSION ioctl failed");
911
912	if (bv.bv_major != BPF_MAJOR_VERSION ||
913	    bv.bv_minor < BPF_MINOR_VERSION)
914		errx(EXIT_FAILURE, "Kernel BPF filter out of date");
915
916	/* USB transfers can be greater than 64KByte */
917	v = 1U << 16;
918
919	/* clear ifr structure */
920	memset(&ifr, 0, sizeof(ifr));
921
922	/* Try to create usbusN interface if it is not available. */
923	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
924	if (s < 0)
925		errx(EXIT_FAILURE, "Could not open a socket");
926	ifindex = if_nametoindex(i_arg);
927	if (ifindex == 0) {
928		(void)strlcpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name));
929		if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
930			errx(EXIT_FAILURE, "Invalid bus interface: %s", i_arg);
931	}
932
933	for ( ; v >= USBPF_HDR_LEN; v >>= 1) {
934		(void)ioctl(fd, BIOCSBLEN, (caddr_t)&v);
935		(void)strlcpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name));
936		if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
937			break;
938	}
939	if (v == 0)
940		errx(EXIT_FAILURE, "No buffer size worked.");
941
942	if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0)
943		err(EXIT_FAILURE, "BIOCGBLEN ioctl failed");
944
945	p->bufsize = v;
946	p->buffer = (uint8_t *)malloc(p->bufsize);
947	if (p->buffer == NULL)
948		errx(EX_SOFTWARE, "Out of memory.");
949
950	make_filter(&total_prog, snapshot);
951
952	if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0)
953		err(EXIT_FAILURE, "BIOCSETF ioctl failed");
954
955	free_filter(&total_prog);
956
957	/* 1 second read timeout */
958	tv.tv_sec = 1;
959	tv.tv_usec = 0;
960	if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&tv) < 0)
961		err(EXIT_FAILURE, "BIOCSRTIMEOUT ioctl failed");
962
963	(void)signal(SIGINT, handle_sigint);
964
965	do_loop(p);
966
967	if (ioctl(fd, BIOCGSTATS, (caddr_t)&us) < 0)
968		err(EXIT_FAILURE, "BIOCGSTATS ioctl failed");
969
970	/* XXX what's difference between pkt_captured and us.us_recv? */
971	printf("\n");
972	printf("%d packets captured\n", pkt_captured);
973	printf("%d packets received by filter\n", us.bs_recv);
974	printf("%d packets dropped by kernel\n", us.bs_drop);
975
976	/*
977	 * Destroy the usbusN interface only if it was created by
978	 * usbdump(8).  Ignore when it was already destroyed.
979	 */
980	if (ifindex == 0 && if_nametoindex(i_arg) > 0) {
981		(void)strlcpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name));
982		if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
983			warn("SIOCIFDESTROY ioctl failed");
984	}
985	close(s);
986
987	if (p->fd > 0)
988		close(p->fd);
989	if (p->rfd > 0)
990		close(p->rfd);
991	if (p->wfd > 0)
992		close(p->wfd);
993	if (p->bfd > 0)
994		close(p->bfd);
995
996	return (EXIT_SUCCESS);
997}
998