Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Feb 2012 21:18:36 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r231835 - head/usr.sbin/usbdump
Message-ID:  <201202162118.q1GLIbk7034752@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Thu Feb 16 21:18:36 2012
New Revision: 231835
URL: http://svn.freebsd.org/changeset/base/231835

Log:
  Add support for filtering USB devices and USB endpoints to the usbdump utility
  when making software USB traces.
  
  MFC after: 1 week

Modified:
  head/usr.sbin/usbdump/usbdump.8
  head/usr.sbin/usbdump/usbdump.c

Modified: head/usr.sbin/usbdump/usbdump.8
==============================================================================
--- head/usr.sbin/usbdump/usbdump.8	Thu Feb 16 21:04:47 2012	(r231834)
+++ head/usr.sbin/usbdump/usbdump.8	Thu Feb 16 21:18:36 2012	(r231835)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd May 31, 2011
+.Dd February 16, 2012
 .Dt USBDUMP 8
 .Os
 .Sh NAME
@@ -38,6 +38,7 @@
 .Op Fl s Ar snaplen
 .Op Fl v
 .Op Fl w Ar file
+.Op Fl f Ar filter
 .Sh DESCRIPTION
 The
 .Nm
@@ -61,6 +62,16 @@ When defined multiple times the verbosit
 .It Fl w Ar file
 Write the raw packets to
 .Ar file .
+.It Fl f Ar filter
+The filter argument consists of either one or two numbers separated by a dot.
+The first indicates the device unit number which should be traced.
+The second number which is optional indicates the endpoint which should be traced.
+To get all traffic for the control endpoint, two filters should be
+created, one for endpoint 0 and one for endpoint 128.
+If 128 is added to the endpoint number that means IN direction, else OUT direction is implied.
+A device unit or endpoint value of -1 means ignore this field.
+If no filters are specified, all packets are passed through using the default -1,-1 filter.
+This option can be specified multiple times.
 .El
 .Sh EXAMPLES
 Capture the USB raw packets on usbus2:
@@ -72,6 +83,11 @@ size limit:
 .Pp
 .Dl "usbdump -i usbus2 -s 0 -w /tmp/dump_pkts"
 .Pp
+Dump the USB raw packets of usbus2, but only the control endpoint traffic
+of device unit number 3:
+.Pp
+.Dl "usbdump -i usbus2 -s 0 -f 3.0 -f 3.128 -w /tmp/dump_pkts"
+.Pp
 Read and display the USB raw packets from previous file:
 .Pp
 .Dl "usbdump -r /tmp/dump_pkts -v"

Modified: head/usr.sbin/usbdump/usbdump.c
==============================================================================
--- head/usr.sbin/usbdump/usbdump.c	Thu Feb 16 21:04:47 2012	(r231834)
+++ head/usr.sbin/usbdump/usbdump.c	Thu Feb 16 21:18:36 2012	(r231835)
@@ -35,6 +35,7 @@
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/utsname.h>
+#include <sys/queue.h>
 #include <net/if.h>
 #include <net/bpf.h>
 #include <dev/usb/usb.h>
@@ -45,12 +46,33 @@
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 #include <sysexits.h>
 #include <err.h>
 
+#define	BPF_STORE_JUMP(x,_c,_k,_jt,_jf) do {	\
+  (x).code = (_c);				\
+  (x).k = (_k);					\
+  (x).jt = (_jt);				\
+  (x).jf = (_jf);				\
+} while (0)
+
+#define	BPF_STORE_STMT(x,_c,_k) do {		\
+  (x).code = (_c);				\
+  (x).k = (_k);					\
+  (x).jt = 0;					\
+  (x).jf = 0;					\
+} while (0)
+
+struct usb_filt {
+	STAILQ_ENTRY(usb_filt) entry;
+	int unit;
+	int endpoint;
+};
+
 struct usbcap {
 	int		fd;		/* fd for /dev/usbpf */
 	uint32_t	bufsize;
@@ -123,6 +145,114 @@ static const char *speed_table[USB_SPEED
 	[USB_SPEED_SUPER] = "SUPER",
 };
 
+static STAILQ_HEAD(,usb_filt) usb_filt_head =
+    STAILQ_HEAD_INITIALIZER(usb_filt_head);
+
+static void
+add_filter(int usb_filt_unit, int usb_filt_ep)
+{
+	struct usb_filt *puf;
+
+	puf = malloc(sizeof(struct usb_filt));
+	if (puf == NULL)
+		errx(EX_SOFTWARE, "Out of memory.");
+
+	puf->unit = usb_filt_unit;
+	puf->endpoint = usb_filt_ep;
+
+	STAILQ_INSERT_TAIL(&usb_filt_head, puf, entry);
+}
+
+static void
+make_filter(struct bpf_program *pprog, int snapshot)
+{
+	struct usb_filt *puf;
+	struct bpf_insn *dynamic_insn;
+	int len;
+
+	len = 0;
+
+	STAILQ_FOREACH(puf, &usb_filt_head, entry)
+		len++;
+
+	dynamic_insn = malloc(((len * 5) + 1) * sizeof(struct bpf_insn));
+
+	if (dynamic_insn == NULL)
+		errx(EX_SOFTWARE, "Out of memory.");
+
+	len++;
+
+	if (len == 1) {
+		/* accept all packets */
+
+		BPF_STORE_STMT(dynamic_insn[0], BPF_RET | BPF_K, snapshot);
+
+		goto done;
+	}
+
+	len = 0;
+
+	STAILQ_FOREACH(puf, &usb_filt_head, entry) {
+		const int addr_off = (uintptr_t)&((struct usbpf_pkthdr *)0)->up_address;
+		const int addr_ep = (uintptr_t)&((struct usbpf_pkthdr *)0)->up_endpoint;
+		
+		if (puf->unit != -1) {
+			if (puf->endpoint != -1) {
+				BPF_STORE_STMT(dynamic_insn[len],
+				    BPF_LD | BPF_B | BPF_ABS, addr_off);
+				len++;
+				BPF_STORE_JUMP(dynamic_insn[len],
+				    BPF_JMP | BPF_JEQ | BPF_K, (uint8_t)puf->unit, 0, 3);
+				len++;
+				BPF_STORE_STMT(dynamic_insn[len],
+				    BPF_LD | BPF_W | BPF_ABS, addr_ep);
+				len++;
+				BPF_STORE_JUMP(dynamic_insn[len],
+				    BPF_JMP | BPF_JEQ | BPF_K, htobe32(puf->endpoint), 0, 1);
+				len++;
+			} else {
+				BPF_STORE_STMT(dynamic_insn[len],
+				    BPF_LD | BPF_B | BPF_ABS, addr_off);
+				len++;
+				BPF_STORE_JUMP(dynamic_insn[len],
+				    BPF_JMP | BPF_JEQ | BPF_K, (uint8_t)puf->unit, 0, 1);
+				len++;
+			}
+		} else {
+			if (puf->endpoint != -1) {
+				BPF_STORE_STMT(dynamic_insn[len],
+				    BPF_LD | BPF_W | BPF_ABS, addr_ep);
+				len++;
+				BPF_STORE_JUMP(dynamic_insn[len],
+				    BPF_JMP | BPF_JEQ | BPF_K, htobe32(puf->endpoint), 0, 1);
+				len++;
+			}
+		}
+		BPF_STORE_STMT(dynamic_insn[len],
+		    BPF_RET | BPF_K, snapshot);
+		len++;
+	}
+
+	BPF_STORE_STMT(dynamic_insn[len], BPF_RET | BPF_K, 0);
+	len++;
+
+done:
+	pprog->bf_len = len;
+	pprog->bf_insns = dynamic_insn;
+}
+
+static void
+free_filter(struct bpf_program *pprog)
+{
+	struct usb_filt *puf;
+
+	while ((puf = STAILQ_FIRST(&usb_filt_head)) != NULL) {
+		STAILQ_REMOVE_HEAD(&usb_filt_head, entry);
+		free(puf);
+	}
+	free(pprog->bf_insns);
+}
+
 static void
 handle_sigint(int sig)
 {
@@ -527,6 +657,7 @@ usage(void)
 #define FMT "    %-14s %s\n"
 	fprintf(stderr, "usage: usbdump [options]\n");
 	fprintf(stderr, FMT, "-i <usbusX>", "Listen on USB bus interface");
+	fprintf(stderr, FMT, "-f <unit[.endpoint]>", "Specify a device and endpoint filter");
 	fprintf(stderr, FMT, "-r <file>", "Read the raw packets from file");
 	fprintf(stderr, FMT, "-s <snaplen>", "Snapshot bytes from each packet");
 	fprintf(stderr, FMT, "-v", "Increase the verbose level");
@@ -539,7 +670,6 @@ int
 main(int argc, char *argv[])
 {
 	struct timeval tv;
-	struct bpf_insn total_insn;
 	struct bpf_program total_prog;
 	struct bpf_stat us;
 	struct bpf_version bv;
@@ -547,12 +677,16 @@ main(int argc, char *argv[])
 	struct ifreq ifr;
 	long snapshot = 192;
 	uint32_t v;
-	int fd, o;
+	int fd;
+	int o;
+	int filt_unit;
+	int filt_ep;
 	const char *optstring;
+	char *pp;
 
 	memset(&uc, 0, sizeof(struct usbcap));
 
-	optstring = "i:r:s:vw:";
+	optstring = "i:r:s:vw:f:";
 	while ((o = getopt(argc, argv, optstring)) != -1) {
 		switch (o) {
 		case 'i':
@@ -563,8 +697,10 @@ main(int argc, char *argv[])
 			init_rfile(p);
 			break;
 		case 's':
-			snapshot = strtol(optarg, NULL, 10);
+			snapshot = strtol(optarg, &pp, 10);
 			errno = 0;
+			if (pp != NULL && *pp != 0)
+				usage();
 			if (snapshot == 0 && errno == EINVAL)
 				usage();
 			/* snapeshot == 0 is special */
@@ -578,6 +714,20 @@ main(int argc, char *argv[])
 			w_arg = optarg;
 			init_wfile(p);
 			break;
+		case 'f':
+			filt_unit = strtol(optarg, &pp, 10);
+			filt_ep = -1;
+			if (pp != NULL) {
+				if (*pp == '.') {
+					filt_ep = strtol(pp + 1, &pp, 10);
+					if (pp != NULL && *pp != 0)
+						usage();
+				} else if (*pp != 0) {
+					usage();
+				}
+			}
+			add_filter(filt_unit, filt_ep);
+			break;
 		default:
 			usage();
 			/* NOTREACHED */
@@ -623,17 +773,13 @@ main(int argc, char *argv[])
 	if (p->buffer == NULL)
 		errx(EX_SOFTWARE, "Out of memory.");
 
-	/* XXX no read filter rules yet so at this moment accept everything */
-	total_insn.code = (u_short)(BPF_RET | BPF_K);
-	total_insn.jt = 0;
-	total_insn.jf = 0;
-	total_insn.k = snapshot;
+	make_filter(&total_prog, snapshot);
 
-	total_prog.bf_len = 1;
-	total_prog.bf_insns = &total_insn;
 	if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0)
 		err(EXIT_FAILURE, "BIOCSETF ioctl failed");
 
+	free_filter(&total_prog);
+
 	/* 1 second read timeout */
 	tv.tv_sec = 1;
 	tv.tv_usec = 0;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202162118.q1GLIbk7034752>