From owner-svn-src-all@FreeBSD.ORG Thu Feb 16 21:18:37 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 32095106566B; Thu, 16 Feb 2012 21:18:37 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 1FFF48FC0C; Thu, 16 Feb 2012 21:18:37 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q1GLIbPd034755; Thu, 16 Feb 2012 21:18:37 GMT (envelope-from hselasky@svn.freebsd.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q1GLIbk7034752; Thu, 16 Feb 2012 21:18:37 GMT (envelope-from hselasky@svn.freebsd.org) Message-Id: <201202162118.q1GLIbk7034752@svn.freebsd.org> From: Hans Petter Selasky Date: Thu, 16 Feb 2012 21:18:36 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r231835 - head/usr.sbin/usbdump X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 16 Feb 2012 21:18:37 -0000 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 #include #include +#include #include #include #include @@ -45,12 +46,33 @@ #include #include #include +#include #include #include #include #include #include +#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 ", "Listen on USB bus interface"); + fprintf(stderr, FMT, "-f ", "Specify a device and endpoint filter"); fprintf(stderr, FMT, "-r ", "Read the raw packets from file"); fprintf(stderr, FMT, "-s ", "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;