ANNOUNCEMENT: Live Wireshark University & Allegro Packets online APAC Wireshark Training Session
April 17th, 2024 | 14:30-16:00 SGT (UTC+8) | Online

Wireshark-dev: [Wireshark-dev] [PATCH] enable sniff on USB ports

From: abeni <paolo.abeni@xxxxxxxx>
Date: Tue, 19 Sep 2006 15:02:19 +0200
Hi list,

I'm trying to plug USB sniffing support into wireshark, at least under
Linux. I have some working code (the attached patch, against revision
19257), but is quite intrusive, it uses the usbmon infrastructure and
works only on with recent Linux kernels (I think 2.6.8 or newer is
needed).

The patch build up a generic 'virtual' API for sniffing that is
'hardware agnostic'. The API is instantiated on the pcap library, for
ethernet sniffing, and on a glue a build up around the usbmon interface,
for USB sniffing. 

I also added a basic USB dissector to show raw URB data contents.

The get the USB sniffing functionality working you need to mount the
debug file system in /sys/kernel/debug:

mount -t debugfs / /sys/kernel/debug 

If everything works, you should be able to see various usb<number>
interfaces in the wireshark/tshark/dumpcap interfaces list. You will get
an interface usbX for each detected USB bus on the running host.

Any feedback is very welcome.

ciao,
	Paolo


 
 
 --
 Email.it, the professional e-mail, gratis per te: http://www.email.it/f
 
 Sponsor:
 Refill s.r.l. - Tutto per la tua stampante a prezzi incredibili: su cartucce, toner, inchiostri, carta speciale risparmi fino al 90%!
 Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=5189&d=19-9
Index: capture-if.c
===================================================================
--- capture-if.c	(revision 0)
+++ capture-if.c	(revision 0)
@@ -0,0 +1,165 @@
+/* capture-if.c
+ *
+ * $Id$
+ *
+ * Abstract sniffing API
+ * By Paolo Abeni <paolo.abeni@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+ 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif 
+ 
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef NEED_STRERROR_H
+#include "strerror.h"
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <pcap.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <glib.h> 
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+
+#include <wiretap/wtap.h>
+
+#include "pcapio.h"
+#include "capture.h"
+#include "capture-pcap-util.h"
+#include "capture-pcap-util-int.h"
+#include "capture_loop.h"
+
+#include "capture-usb.h"
+#include "capture-if.h"
+
+static int 
+dummy_pcap_setbuff( void *a _U_, int b _U_ )
+{
+    return 0;
+}
+
+static if_ops pcap_ops = {
+#ifdef HAVE_PCAP_GET_SELECTABLE_FD
+    (if_fileno)pcap_get_selectable_fd,
+#else
+    (if_fileno)pcap_fileno,
+#endif    
+    (if_dispatch)pcap_dispatch,
+    (if_open_live)pcap_open_live,
+    (if_close)pcap_close,
+    (if_stats)pcap_stats,
+    (if_snapshot) pcap_snapshot,
+    (if_geterr)pcap_geterr,
+    get_pcap_linktype_list,
+    (if_get_linktype)get_pcap_linktype,
+    (if_set_linktype)set_pcap_linktype,
+    (if_compile) pcap_compile,
+    (if_setfilter) pcap_setfilter,    
+#ifdef HAVE_PCAP_BREAKLOOP
+    (if_breakloop) pcap_breakloop,
+#else
+     0,
+#endif    
+#ifndef _WIN32
+    dummy_pcap_setbuff
+#else
+    (if_setbuff) pcap_setbuff
+#endif   
+};
+
+#ifdef HAVE_USB_SNIFFER 
+static if_ops usb_ops = {
+    (if_fileno)usb_fileno,
+    (if_dispatch)usb_dispatch,
+    (if_open_live)usb_open_live,
+    (if_close)usb_close,
+    (if_stats)usb_stats,
+    (if_snapshot) usb_snapshot,
+    (if_geterr)usb_geterr,
+    usb_get_linktype_list,
+    (if_get_linktype)usb_get_linktype,
+    (if_set_linktype)usb_set_linktype,
+    (if_compile) usb_compile,
+    (if_setfilter) usb_setfilter,
+    (if_breakloop) usb_breakloop,
+    (if_setbuff) usb_setbuff
+    
+};
+#endif /* HAVE_USB_SNIFFER */
+
+
+
+GList *
+get_interface_list(int *err, char *err_str)
+{
+    GList* il =  get_net_interface_list(err, err_str);
+#ifdef HAVE_USB_SNIFFER
+    GList* other_il =  usb_find_all_devs(err, err_str);
+    il = g_list_concat(il, other_il);
+#endif
+    return il;
+}
+
+static gint
+if_compare(gconstpointer a, gconstpointer name)
+{
+    return strcmp(((if_info_t*)a)->name, (gchar*)name);
+}
+
+if_info_t *
+if_find(GList* list, const char* name)
+{
+    GList* item = g_list_find_custom(list, name, if_compare);
+    if (item)
+        return (if_info_t*)item->data;
+    return 0;
+}
+
+if_ops 
+if_get_ops(const char* name)
+{
+    if_ops ops = pcap_ops;
+    GList* il = 0;
+#ifdef HAVE_USB_SNIFFER    
+    char errmsg[PCAP_ERRBUF_SIZE];
+    int err;
+    il = usb_find_all_devs(&err, errmsg);
+    if (if_find(il, name))
+        ops = usb_ops;
+    free_interface_list(il);
+#endif 
+    return ops;
+}
+
+GList* 
+get_linktype_list(const char * name, char *errbuf)
+{
+    if_ops ops = if_get_ops(name);
+    return ops.get_linktype_list(name, errbuf);
+}
Index: capture-if.h
===================================================================
--- capture-if.h	(revision 0)
+++ capture-if.h	(revision 0)
@@ -0,0 +1,65 @@
+/* capture-if.h
+ *
+ * $Id$
+ *
+ * Abstract sniffing API
+ * By Paolo Abeni <paolo.abeni@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+ 
+#ifndef __CAPTURE_IF_H__
+#define __CAPTURE_IF_H__
+
+typedef int (*if_fileno)(void*);
+typedef int (*if_dispatch)(void*, int, pcap_handler, u_char *);
+typedef void* (*if_open_live)(const char* , int , int , int , char* );
+typedef void (*if_close)(void*);
+typedef int (*if_snapshot)(void*);
+typedef int (*if_stats)(void *, struct pcap_stat *);
+typedef char *(*if_geterr)(void *);
+typedef GList *(*if_get_linktype_list)(const char *, char *);
+typedef int(*if_get_linktype)(void *, const char*);
+typedef const char *(*if_set_linktype)(void *, char *devname, int dlt);
+typedef int (*if_setbuff)( void *a, int b);
+typedef int (*if_compile)(void *, struct bpf_program *, char *, int , bpf_u_int32 );
+typedef int (*if_setfilter)(void *, struct bpf_program *);
+typedef int (*if_next_ex)(void *, struct pcap_pkthdr **, const u_char **);
+typedef int (*if_breakloop)(void *);
+
+
+typedef struct _if_ops {
+    if_fileno fileno;
+    if_dispatch dispatch;
+    if_open_live open_live;
+    if_close close;
+    if_stats stats;
+    if_snapshot snapshot;
+    if_geterr geterr;
+    if_get_linktype_list get_linktype_list;
+    if_get_linktype get_linktype;
+    if_set_linktype set_linktype;
+    if_compile compile;
+    if_setfilter setfilter;
+    if_breakloop breakloop;
+    if_setbuff setbuff;
+} if_ops;
+
+
+extern if_info_t* if_find(GList* list, const char* name);
+extern if_ops if_get_ops(const char* name);
+extern GList* get_linktype_list(const char * name, char *errbuf);
+
+#endif
Index: configure.in
===================================================================
--- configure.in	(revision 19257)
+++ configure.in	(working copy)
@@ -1332,6 +1332,22 @@
 fi
 AC_SUBST(ENABLE_STATIC)
 
+dnl PAOLO check for usb sniffing support
+AC_MSG_CHECKING(for USB sniffing support)
+case "$host_os" in
+linux*)
+  	AC_DEFINE(HAVE_USB_SNIFFER, 1, [target host support usb sniffing])
+        AC_DEFINE(HAVE_USB_LINUX_SNIFFER, 1, [target host is linux and support usb sniffing])
+        usb_objects=capture-usb-linux.o
+        AC_MSG_RESULT(yes)
+	;;
+*)
+	AC_MSG_RESULT(no)
+	;;
+esac
+AC_SUBST(HAVE_USB_SNIFFER)
+AC_SUBST(usb_objects)
+
 dnl Save the cacheable configure results to config.cache before recursing
 AC_CACHE_SAVE
 
Index: capture-usb-linux.c
===================================================================
--- capture-usb-linux.c	(revision 0)
+++ capture-usb-linux.c	(revision 0)
@@ -0,0 +1,426 @@
+/* capture-usb-linux.c
+ *
+ * $Id$
+ *
+ * USB sniffig API implementation for linux platform
+ * By Paolo Abeni <paolo.abeni@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+ 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif 
+ 
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef NEED_STRERROR_H
+#include "strerror.h"
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <pcap.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <glib.h> 
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+
+#include <wiretap/wtap.h>
+#include <wiretap/wtap-capture.h>
+
+#include "pcapio.h"
+#include "capture.h"
+#include "capture-pcap-util.h"
+#include "capture-pcap-util-int.h"
+#include "capture_loop.h"
+
+#include "capture-usb.h"
+#include "usb-structs.h"
+
+#define USB_IFACE "usb"
+#define USB_DIR "/sys/kernel/debug/usbmon"
+#define USB_LINKTYPE 147
+#define USB_LINE_LEN 4096
+
+struct pusb {
+    int n_packets;
+    int fd;
+    char stat_path[USB_LINE_LEN];
+    char errmsg[PCAP_ERRBUF_SIZE];
+    gboolean loop;
+};
+ 
+GList *
+usb_find_all_devs(int *err, char *err_str)
+{
+  GList * il=0;
+  const gchar* name;
+  GDir * dir = g_dir_open(USB_DIR, 0, 0);
+  if (!dir) {
+    *err = CANT_GET_INTERFACE_LIST;
+    g_snprintf(err_str, PCAP_ERRBUF_SIZE, 
+"can't open "USB_DIR" ensure debugfs is mounted \n"
+"mount -t debugfs none_debugs /sys/kernel/debug\n"
+"and usbmon is supported");
+    return 0;
+  }
+  
+  
+  /* scan usbmon directory */
+  while ((name = g_dir_read_name(dir)) != 0)
+  {
+    if (g_str_has_suffix(name, "s"))
+    {
+      if_info_t* if_info;
+      int n = name[0] - '0';
+      char dev_name[10], dev_desrc[20];
+      g_sprintf(dev_name, USB_IFACE"%d", n);
+      g_sprintf(dev_desrc, "usb bus number %d", n);
+      
+      if_info = if_info_new(dev_name, dev_desrc);
+      il = g_list_append(il, if_info);
+    }
+  }
+  g_dir_close(dir);
+  
+  return il;
+}
+
+pusb_t*
+usb_open_live(const char* bus, int snap _U_, int promisc _U_, int ms _U_, char* errmsg)
+{
+  gchar full_path[128];
+  gint usb_bus_num;
+  sscanf(bus, USB_IFACE"%d", &usb_bus_num);
+  pusb_t* hdr = g_malloc(sizeof(pusb_t));
+
+  /* open text output file*/
+  g_snprintf(full_path, 128, USB_DIR"/%dt", usb_bus_num);  
+  hdr->fd = g_open(full_path, O_RDONLY, 0);
+  if (hdr->fd < 0)
+  {
+    g_snprintf(errmsg, PCAP_ERRBUF_SIZE,
+      "Can't open usb bus file %s: %s", full_path, strerror(errno));
+    g_free(hdr);
+    return 0;
+  }
+  
+  /* memorize stats file path */
+  g_snprintf(hdr->stat_path, 128, USB_DIR"/%ds", usb_bus_num);    
+  return hdr;
+}
+
+static inline 
+int ascii_to_int(char c)
+{
+  return c < 'A' ? c- '0': ((c<'a') ? c- 'A': c-'a');
+}
+
+/*
+ * see <linux-kernel-source>/Documentation/usb/usbmon.txt and 
+ * <linux-kernel-source>/drivers/usb/mon/mon_text.c for urb string 
+ * format description
+ */
+int 
+usb_dispatch(pusb_t* hnd, int limit _U_, pcap_handler packet_cb,  u_char *user)
+{
+  /* see:
+   * /usr/src/linux/Documentation/usb/usbmon.txt 
+   * for message format
+   */
+  unsigned timestamp;
+  int tag, cnt, ep_num, dev_addr, dummy, ret;
+  char stringstore[USB_LINE_LEN], etype, pipeid1, pipeid2, status[16], urb_tag;
+  char *string=stringstore, *errmsg = hnd->errmsg;
+  guchar rawdatastore[USB_LINE_LEN];
+  guchar * rawdata = rawdatastore;
+  struct pcap_pkthdr pkth;
+  usb_header* uhdr = (usb_header*)rawdata;
+  urb_type_t urb_type = URB_UNKNOWN;
+  
+  /* ignore interrupt system call errors */
+  hnd->loop = TRUE;
+  do {
+      ret = read(hnd->fd, string, USB_LINE_LEN - 1);
+      if (hnd->loop == FALSE)
+          return -2;
+  } while ((ret == -1) && (errno == EINTR));
+  if (ret < 0)
+  {
+    g_snprintf(errmsg, PCAP_ERRBUF_SIZE,
+        "Can't read from fd %d: %s", hnd->fd, strerror(errno));
+    return -1;
+  }
+   
+  /* read urb header; %n argument may increment return value, but it's 
+   * not mandatory, so does not count on it*/
+  string[ret] = 0;
+  ret = sscanf(string, "%x %d %c %c%c:%d:%d %s%n", &tag, &timestamp, &etype, 
+    &pipeid1, &pipeid2, &dev_addr, &ep_num, status, 
+    &cnt);
+  if (ret < 8)
+  {
+    g_snprintf(errmsg, PCAP_ERRBUF_SIZE,
+        "Can't parse usb bus message '%s', too few token (expected 8 got %d)",
+        string, ret);
+    return -1;
+  }
+  uhdr->endpoint_number = g_htonl(ep_num);
+  uhdr->device_address = g_htonl(dev_addr);
+  string += cnt;
+  pkth.ts.tv_sec = timestamp / 1000000;
+  pkth.ts.tv_usec = timestamp % 1000000;
+  
+  /* parse endpoint information */
+  if (pipeid1 == 'C')
+  {
+    if (pipeid2 =='i')
+      urb_type = URB_CONTROL_INPUT;
+    else
+      urb_type = URB_CONTROL_OUTPUT;
+  }
+  else if (pipeid1 == 'Z')
+  {
+    if (pipeid2 == 'i')
+      urb_type = URB_ISOCHRONOUS_INPUT;
+    else 
+      urb_type = URB_ISOCHRONOUS_OUTPUT;
+  }
+  else if (pipeid1 == 'I')
+  {
+    if (pipeid2 == 'i')
+      urb_type = URB_INTERRUPT_INPUT;
+    else
+      urb_type = URB_INTERRUPT_OUTPUT;
+  }
+  else if (pipeid1 == 'B')
+  {
+    if (pipeid2 == 'i')
+      urb_type = URB_BULK_INPUT;
+    else
+      urb_type = URB_BULK_OUTPUT;
+  }
+  uhdr->urb_type = g_htonl(urb_type);
+  pkth.caplen = sizeof(usb_header);
+  rawdata += sizeof(usb_header);
+  
+  /* check if this is a setup packet */
+  ret = sscanf(status, "%d", &dummy);
+  if (ret == 0)
+  {
+    /* this a setup packet, setup data can be filled with underscore if
+     * usbmon has not been able to read them, so we must parse this fields as 
+     * strings */
+    usb_setup* shdr;
+    char str1[3], str2[3], str3[5], str4[5], str5[5];
+    ret = sscanf(string, "%s %s %s %s %s%n", str1, str2, str3, str4, 
+      str5, &cnt);
+    if (ret < 5)
+    {
+      g_snprintf(errmsg, PCAP_ERRBUF_SIZE,
+        "Can't parse usb bus message '%s', too few token (expected 5 got %d)",
+        string, ret);
+      return -1;
+    }
+    string += cnt;
+    
+    /* try to convert to corresponding integer */
+    shdr = (usb_setup*)rawdata;
+    shdr->bmRequestType = g_htonl(strtol(str1, 0, 16));
+    shdr->bRequest = g_htonl(strtol(str2, 0, 16));
+    shdr->wValue = g_htonl(strtol(str3, 0, 16));
+    shdr->wIndex = g_htonl(strtol(str4, 0, 16));
+    shdr->wLength = g_htonl(strtol(str5, 0, 16));
+    
+    pkth.caplen = sizeof(usb_setup);
+    rawdata += sizeof(usb_setup);
+  }
+  
+  /* read urb data */
+  ret = sscanf(string, " %d%n", &pkth.len, &cnt);
+  if (ret < 1)
+  {
+    g_snprintf(errmsg, PCAP_ERRBUF_SIZE,
+      "Can't parse urb length from '%s'", string);
+    return -1;
+  }
+  string += cnt;
+  hnd->n_packets++;
+  
+  /* urb tag is not present if urb length is 0 */
+  pkth.len += pkth.caplen;
+  if (pkth.len == pkth.caplen)
+      return 1;
+  
+  /* check for data presence */
+  if (sscanf(string, " %c", &urb_tag) != 1)
+  {
+    g_snprintf(errmsg, PCAP_ERRBUF_SIZE,
+      "Can't parse urb tag from '%s'", string);
+    return -1;
+  }
+  if (urb_tag != '=')
+  {
+    packet_cb(user, &pkth, rawdatastore);
+    return 1;
+  }
+  
+  /* read all urb data; if urb length is less then our string we get only
+   * a partial information  */
+  while ((string[0] != 0) && (string[1] != 0))
+  {
+    rawdata[0] = ascii_to_int(string[0]) * 16 + ascii_to_int(string[1]);
+    rawdata++;
+    string+=2;
+    if (string[0] == ' ')
+      string++;
+    pkth.caplen++;
+  }
+  packet_cb(user, &pkth, rawdatastore);
+  return 1;
+}
+
+void
+usb_close(pusb_t* hnd)
+{
+    close(hnd->fd);
+    g_free(hnd);
+}
+
+
+int 
+usb_snapshot(pusb_t* hnd _U_)
+{
+    return USB_LINE_LEN;
+}
+
+char *
+usb_geterr(pusb_t * hdr)
+{
+    return hdr->errmsg;
+}
+
+
+int 
+usb_stats(pusb_t *hdr, struct pcap_stat *stats)
+{
+    int dummy, ret;
+    char string[USB_LINE_LEN];
+    int fd = g_open(hdr->stat_path, O_RDONLY, 0);
+    if (hdr->fd < 0)
+    {
+        g_snprintf(hdr->errmsg, PCAP_ERRBUF_SIZE,
+          "Can't open usb stats file %s: %s", hdr->stat_path, strerror(errno));
+        return 0;
+    }
+    
+    /* read stats line */
+    do {
+        ret = read(fd, string, USB_LINE_LEN-1);
+    } while ((ret == -1) && (errno == EINTR));
+    close(fd);
+    if (ret < 0)
+    {
+        g_snprintf(hdr->errmsg, PCAP_ERRBUF_SIZE,
+          "Can't read stats from file '%s' fd %d ", hdr->stat_path, fd);
+        return -1;
+    }
+    string[ret] = 0;
+    
+    /* extract info on dropped urbs */
+    ret = sscanf(string, "nreaders %d text_lost %d", &dummy, &stats->ps_drop);
+    if (ret != 2)
+    {
+        g_snprintf(hdr->errmsg, PCAP_ERRBUF_SIZE,
+          "Can't parse stat line '%s' expected 2 token got %d", string, ret);
+        return -1;
+    }
+    
+    stats->ps_recv = hdr->n_packets;
+    stats->ps_ifdrop = 0;
+    return 0;
+}
+
+GList *
+usb_get_linktype_list(const char * name _U_, char * errbuf _U_)
+{
+    int wtap_encap;
+    data_link_info_t *data_link_info = g_malloc(sizeof (data_link_info_t));
+    data_link_info->dlt = USB_LINKTYPE;
+    data_link_info->name = g_strdup_printf("DLT %d", USB_LINKTYPE);
+    wtap_encap = wtap_pcap_encap_to_wtap_encap(USB_LINKTYPE);
+    if (wtap_encap == 0)
+        data_link_info->dlt = USB_LINKTYPE;
+    else
+        data_link_info->description =
+                    g_strdup(wtap_encap_string(wtap_encap));
+    return g_list_append(0, data_link_info);
+}
+
+const char * 
+usb_set_linktype(pusb_t * hdr _U_, char *devname _U_, int dlt)
+{
+    if (dlt == USB_LINKTYPE)
+        return NULL;
+    return "That DLT isn't one of the DLTs supported by this device";
+}
+
+int 
+usb_get_linktype(pusb_t * hdr _U_, const char* name _U_)
+{
+   return USB_LINKTYPE; 
+}
+
+int 
+usb_setbuff(pusb_t *a _U_, int b _U_)
+{
+    return 0;
+}
+
+int 
+usb_compile(pusb_t *p _U_, struct bpf_program *fp _U_,
+               char *str _U_, int optimize _U_, bpf_u_int32 netmask _U_)
+{
+    memset(fp, 0, sizeof(struct bpf_program));
+    return 0;
+}
+
+int 
+usb_setfilter(pusb_t *p _U_, struct bpf_program *fp _U_)
+{
+    return 0;
+}
+
+int 
+usb_fileno(pusb_t* hdr)
+{
+    return hdr->fd;
+}
+
+void 
+usb_breakloop(pusb_t* hnd)
+{
+    hnd->loop = FALSE;
+}
Index: capture-pcap-util.h
===================================================================
--- capture-pcap-util.h	(revision 19257)
+++ capture-pcap-util.h	(working copy)
@@ -74,6 +74,7 @@
 	} ip_addr;
 } if_addr_t;
 
+GList *get_net_interface_list(int *err, char *err_str);
 GList *get_interface_list(int *err, char *err_str);
 
 /* Error values from "get_interface_list()". */
@@ -135,4 +136,6 @@
  */
 extern void get_runtime_pcap_version(GString *str);
 
+#include "capture-if.h"
+
 #endif /* __PCAP_UTIL_H__ */
Index: Makefile.common
===================================================================
--- Makefile.common	(revision 19257)
+++ Makefile.common	(working copy)
@@ -47,6 +47,7 @@
 # sources common for wireshark and tshark
 WIRESHARK_COMMON_SRC =	\
 	$(PLATFORM_SRC) \
+	capture-if.c    \
 	capture_errs.c	\
 	capture-pcap-util.c	\
 	capture_stop_conditions.c	\
@@ -220,6 +221,7 @@
 	$(PLATFORM_SRC) \
 	capture_opts.c \
 	capture_loop.c	\
+	capture-if.c    \
 	capture-pcap-util.c	\
 	capture_stop_conditions.c	\
 	clopts_common.c	\
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 19257)
+++ Makefile.am	(working copy)
@@ -293,7 +293,7 @@
 wireshark_DEPENDENCIES = \
 	$(wireshark_optional_objects)	\
 	$(wireshark_additional_libs)	\
-	$(plugin_libs)
+	$(plugin_libs) $(usb_objects)
 
 # This automake variable adds to the link-line for the executable.
 #
@@ -310,6 +310,7 @@
 endif
 
 wireshark_LDADD = \
+	$(usb_objects)			\
 	$(wireshark_optional_objects)	\
 	$(wireshark_additional_libs)	\
 	@SNMP_LIBS@ @SSL_LIBS@ 		\
@@ -319,7 +320,7 @@
 	@LIBICONV@			\
 	@LIBGCRYPT_LIBS@		\
 	@LIBGNUTLS_LIBS@		\
-	@PORTAUDIO_LIBS@
+	@PORTAUDIO_LIBS@ 
 
 # Additional libs that I know how to build. These will be
 # linked into the tshark executable.
@@ -331,10 +332,11 @@
 tshark_DEPENDENCIES = \
 	$(wireshark_optional_objects)	\
 	$(tshark_additional_libs)	\
-	$(plugin_libs)
+	$(plugin_libs)  $(usb_objects)
 
 # This automake variable adds to the link-line for the executable
 tshark_LDADD = \
+	$(usb_objects)			\
 	$(wireshark_optional_objects)	\
 	$(tshark_additional_libs)	\
 	@SNMP_LIBS@ @SSL_LIBS@		\
@@ -471,9 +473,11 @@
 	wiretap/libwiretap.la
 
 dumpcap_DEPENDENCIES = \
+	$(usb_objects)			\
 	$(dumpcap_additional_libs)
 
 dumpcap_LDADD = \
+	$(usb_objects)			\
 	$(dumpcap_additional_libs)	\
 	@GLIB_LIBS@			\
 	@PCAP_LIBS@ @SOCKET_LIBS@ @NSL_LIBS@
@@ -857,4 +861,3 @@
 
 clean-local:
 	rm -rf $(top_stagedir)
-
Index: usb-structs.h
===================================================================
--- usb-structs.h	(revision 0)
+++ usb-structs.h	(revision 0)
@@ -0,0 +1,53 @@
+/* usb-structs.c
+ *
+ * $Id$
+ *
+ * Basic USB data struct
+ * By Paolo Abeni <paolo.abeni@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+ 
+#ifndef _USB_STRUCTS_H__
+#define _USB_STRUCTS_H__
+
+typedef enum { 
+  URB_CONTROL_INPUT,
+  URB_CONTROL_OUTPUT,
+  URB_ISOCHRONOUS_INPUT,
+  URB_ISOCHRONOUS_OUTPUT,
+  URB_INTERRUPT_INPUT,
+  URB_INTERRUPT_OUTPUT,
+  URB_BULK_INPUT,
+  URB_BULK_OUTPUT,
+  URB_UNKNOWN
+} urb_type_t;
+
+typedef struct _usb_header {
+  guint32 urb_type;  
+  gint32 device_address;
+  gint32 endpoint_number;
+  gint32 setup_packet;
+} usb_header;
+
+typedef struct _usb_setup {
+  guint32 bmRequestType;
+  guint32 bRequest;
+  guint32 wValue;
+  guint32 wIndex;
+  guint32 wLength;
+} usb_setup;
+
+#endif
Index: gtk/capture_if_dlg.c
===================================================================
--- gtk/capture_if_dlg.c	(revision 19257)
+++ gtk/capture_if_dlg.c	(working copy)
@@ -107,7 +107,8 @@
 
 /* the "runtime" data of one interface */
 typedef struct if_dlg_data_s {
-    pcap_t      *pch;
+    if_ops      ops;
+    void        *pch;
     GtkWidget   *device_lb;
     GtkWidget   *descr_lb;
     GtkWidget   *ip_lb;
@@ -209,14 +210,16 @@
    * mechanism, so opening all the devices and presenting packet
    * counts might not always be a good idea.
    */
-  if_dlg_data->pch = pcap_open_live(name,
+  if_dlg_data->ops = if_get_ops(name);
+  if_dlg_data->pch = if_dlg_data->ops.open_live(name,
 		       MIN_PACKET_SIZE,
 		       capture_opts->promisc_mode, CAP_READ_TIMEOUT,
 		       open_err_str);
 
   if (if_dlg_data->pch != NULL) {
     update_if(if_dlg_data);
-  } else {
+  } 
+  else {
     printf("open_if: %s\n", open_err_str);
     gtk_label_set_text(GTK_LABEL(if_dlg_data->curr_lb), "error");
     gtk_label_set_text(GTK_LABEL(if_dlg_data->last_lb), "error");
@@ -243,7 +246,7 @@
    * have the same bug.)
    */
   if (if_dlg_data->pch) {
-    if(pcap_stats(if_dlg_data->pch, &stats) >= 0) {
+    if(if_dlg_data->ops.stats(if_dlg_data->pch, &stats) >= 0) {
 #ifdef _WIN32
       diff = stats.ps_recv - if_dlg_data->last_packets;
       if_dlg_data->last_packets = stats.ps_recv;
@@ -274,7 +277,7 @@
 close_if(if_dlg_data_t *if_dlg_data)
 {
     if(if_dlg_data->pch)
-        pcap_close(if_dlg_data->pch);
+        if_dlg_data->ops.close(if_dlg_data->pch);
 }
 
 
Index: capture-pcap-util-unix.c
===================================================================
--- capture-pcap-util-unix.c	(revision 19257)
+++ capture-pcap-util-unix.c	(working copy)
@@ -74,7 +74,7 @@
 #endif
 
 GList *
-get_interface_list(int *err, char *err_str)
+get_net_interface_list(int *err, char *err_str)
 {
 #ifdef HAVE_PCAP_FINDALLDEVS
 	return get_interface_list_findalldevs(err, err_str);
Index: capture_loop.c
===================================================================
--- capture_loop.c	(revision 19257)
+++ capture_loop.c	(working copy)
@@ -457,8 +457,8 @@
 
 
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_open_input : %s", capture_opts->iface);
+  ld->ops = if_get_ops(capture_opts->iface);
 
-
 /* XXX - opening Winsock on tshark? */
 
   /* Initialize Windows Socket if we are in a WIN32 OS
@@ -512,17 +512,17 @@
      if they succeed; to tell if that's happened, we have to clear
      the error buffer, and check if it's still a null string.  */
   open_err_str[0] = '\0';
-  ld->pcap_h = pcap_open_live(capture_opts->iface,
+  ld->if_h = ld->ops.open_live(capture_opts->iface,
 		       capture_opts->has_snaplen ? capture_opts->snaplen :
 						  WTAP_MAX_PACKET_SIZE,
 		       capture_opts->promisc_mode, CAP_READ_TIMEOUT,
 		       open_err_str);
 
-  if (ld->pcap_h != NULL) {
+  if (ld->if_h != NULL) {
     /* we've opened "iface" as a network device */
 #ifdef _WIN32
     /* try to set the capture buffer size */
-    if (pcap_setbuff(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024) != 0) {
+    if (ld->ops.setbuff(ld->if_h, capture_opts->buffer_size * 1024 * 1024) != 0) {
         sync_secondary_msg_str = g_strdup_printf(
           "The capture buffer size of %luMB seems to be too high for your machine,\n"
           "the default of 1MB will be used.\n"
@@ -537,7 +537,7 @@
 
     /* setting the data link type only works on real interfaces */
     if (capture_opts->linktype != -1) {
-      set_linktype_err_str = set_pcap_linktype(ld->pcap_h, capture_opts->iface,
+      set_linktype_err_str = ld->ops.set_linktype(ld->if_h, capture_opts->iface,
 	capture_opts->linktype);
       if (set_linktype_err_str != NULL) {
 	g_snprintf(errmsg, errmsg_len, "Unable to set data link type (%s).",
@@ -546,7 +546,7 @@
 	return FALSE;
       }
     }
-    ld->linktype = get_pcap_linktype(ld->pcap_h, capture_opts->iface);
+    ld->linktype = ld->ops.get_linktype(ld->if_h, capture_opts->iface);
   } else {
     /* We couldn't open "iface" as a network device. */
 #ifdef _WIN32
@@ -632,11 +632,7 @@
 /* XXX - will this work for tshark? */
 #ifdef MUST_DO_SELECT
   if (!ld->from_cap_pipe) {
-#ifdef HAVE_PCAP_GET_SELECTABLE_FD
-    ld->pcap_fd = pcap_get_selectable_fd(ld->pcap_h);
-#else
-    ld->pcap_fd = pcap_fileno(ld->pcap_h);
-#endif
+    ld->pcap_fd = ld->ops.fileno(ld->if_h);
   }
 #endif
 
@@ -666,11 +662,11 @@
 #endif
 
   /* if open, close the pcap "input file" */
-  if(ld->pcap_h != NULL) {
+  if(ld->if_h != NULL) {
     g_assert(!ld->from_cap_pipe);
-    pcap_close(ld->pcap_h);
+    ld->ops.close(ld->if_h);
   }
-
+  
 #ifdef _WIN32
   /* Shut down windows sockets */
   WSACleanup();
@@ -679,7 +675,10 @@
 
 
 /* init the capture filter */
-initfilter_status_t capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter) {
+initfilter_status_t capture_loop_init_filter(capture_options *capture_opts, loop_data* ld) {
+  gboolean from_cap_pipe=ld->from_cap_pipe;
+  const gchar * iface=capture_opts->iface;
+  gchar * cfilter = capture_opts->cfilter;
   bpf_u_int32 netnum, netmask;
   gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
   struct bpf_program fcode;
@@ -704,13 +703,13 @@
         "Warning:  Couldn't obtain netmask info (%s).", lookup_net_err_str);*/
       netmask = 0;
     }
-    if (pcap_compile(pcap_h, &fcode, cfilter, 1, netmask) < 0) {
+    if (ld->ops.compile(ld->if_h, &fcode, cfilter, 1, netmask) < 0) {
       /* Treat this specially - our caller might try to compile this
          as a display filter and, if that succeeds, warn the user that
          the display and capture filter syntaxes are different. */
       return INITFILTER_BAD_FILTER;
     }
-    if (pcap_setfilter(pcap_h, &fcode) < 0) {
+    if (ld->ops.setfilter(ld->if_h, &fcode) < 0) {
 #ifdef HAVE_PCAP_FREECODE
       pcap_freecode(&fcode);
 #endif
@@ -740,7 +739,7 @@
   } else
 #endif
   {
-    file_snaplen = pcap_snapshot(ld->pcap_h);
+      file_snaplen = ld->ops.snapshot(ld->if_h);
   }
 
   /* Set up to write to the capture file. */
@@ -810,7 +809,7 @@
   int         sel_ret;
   guchar pcap_data[WTAP_MAX_PACKET_SIZE];
 #endif
-
+  
 #ifndef _WIN32
   if (ld->from_cap_pipe) {
     /* dispatch from capture pipe */
@@ -875,7 +874,7 @@
          * processing immediately, rather than processing all packets
          * in a batch before quitting.
          */
-        inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *)ld);
+        inpkts = ld->ops.dispatch(ld->if_h, 1, ld->packet_cb, (u_char *)ld);
         if (inpkts < 0) {
           ld->pcap_err = TRUE;
           ld->go = FALSE; /* error or pcap_breakloop() - stop capturing */
@@ -905,9 +904,9 @@
        * after processing packets.  We therefore process only one packet
        * at a time, so that we can check the pipe after every packet.
        */
-      inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *) ld);
+      inpkts = ld->ops.dispatch(ld->if_h, 1, ld->packet_cb, (u_char *) ld);
 #else
-      inpkts = pcap_dispatch(ld->pcap_h, -1, ld->packet_cb, (u_char *) ld);
+      inpkts = ld->ops.dispatch(ld->if_h, -1, ld->packet_cb, (u_char *) ld);
 #endif
       if (inpkts < 0) {
         if (inpkts == -1) {
@@ -1141,20 +1140,20 @@
   }
 
   /* init the input filter from the network interface (capture pipe will do nothing) */
-  switch (capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts->iface, capture_opts->cfilter)) {
+  switch (capture_loop_init_filter(capture_opts, &ld)) {
 
   case INITFILTER_NO_ERROR:
     break;
 
   case INITFILTER_BAD_FILTER:
     cfilter_error = TRUE;
-    g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(ld.pcap_h));
+    g_snprintf(errmsg, sizeof(errmsg), "%s", ld.ops.geterr(ld.if_h));
     *secondary_errmsg = '\0';
     goto error;
 
   case INITFILTER_OTHER_ERROR:
     g_snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).",
-               pcap_geterr(ld.pcap_h));
+               ld.ops.geterr(ld.if_h));
     g_snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report);
     goto error;
   }
@@ -1356,7 +1355,7 @@
   /* did we had a pcap (input) error? */
   if (ld.pcap_err) {
     g_snprintf(errmsg, sizeof(errmsg), "Error while capturing packets: %s",
-      pcap_geterr(ld.pcap_h));
+      ld.ops.geterr(ld.if_h));
     report_capture_error(errmsg, please_report);
   }
 #ifndef _WIN32
@@ -1405,18 +1404,18 @@
    */
 
   /* get packet drop statistics from pcap */
-  if(ld.pcap_h != NULL) {
+  if(ld.if_h != NULL) {
     g_assert(!ld.from_cap_pipe);
     /* Get the capture statistics, so we know how many packets were
        dropped. */
-    if (pcap_stats(ld.pcap_h, stats) >= 0) {
+    if (ld.ops.stats(ld.if_h, stats) >= 0) {
       *stats_known = TRUE;
       /* Let the parent process know. */
       report_packet_drops(stats->ps_drop);
     } else {
       g_snprintf(errmsg, sizeof(errmsg),
 		"Can't get packet-drop statistics: %s",
-		pcap_geterr(ld.pcap_h));
+		ld.ops.geterr(ld.if_h));
       report_capture_error(errmsg, please_report);
     }
   }
@@ -1465,7 +1464,7 @@
 void capture_loop_stop(void)
 {
 #ifdef HAVE_PCAP_BREAKLOOP
-  pcap_breakloop(ld.pcap_h);
+  ld.ops.breakloop(ld.if_h);
 #else
   ld.go = FALSE;
 #endif
Index: tshark.c
===================================================================
--- tshark.c	(revision 19257)
+++ tshark.c	(working copy)
@@ -1563,20 +1563,20 @@
   relinquish_special_privs_perm();
 
   /* init the input filter from the network interface (capture pipe will do nothing) */
-  switch (capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts.iface, capture_opts.cfilter)) {
+  switch (capture_loop_init_filter(&capture_opts, &ld)) {
 
   case INITFILTER_NO_ERROR:
     break;
 
   case INITFILTER_BAD_FILTER:
     cfilter_error = TRUE;
-    g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(ld.pcap_h));
+    g_snprintf(errmsg, sizeof(errmsg), "%s", ld.ops.geterr(ld.if_h));
     *secondary_errmsg = '\0';
     goto error;
 
   case INITFILTER_OTHER_ERROR:
     g_snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).",
-               pcap_geterr(ld.pcap_h));
+               ld.ops.geterr(ld.if_h));
     g_snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report);
     goto error;
   }
@@ -1708,7 +1708,7 @@
       inpkts = cap_pipe_dispatch(&ld, pcap_data, errmsg, sizeof errmsg);
     } else
 #endif
-      inpkts = pcap_dispatch(ld.pcap_h, pcap_cnt, ld.packet_cb, (u_char *) &ld);
+      inpkts = ld.ops.dispatch(ld.if_h, pcap_cnt, ld.packet_cb, (u_char *) &ld);
     if (inpkts < 0) {
       /* Error from "pcap_dispatch()", or error or "no more packets" from
          "cap_pipe_dispatch(). */
@@ -1780,7 +1780,7 @@
     } else
 #endif
     {
-      cmdarg_err("Error while capturing packets: %s", pcap_geterr(ld.pcap_h));
+      cmdarg_err("Error while capturing packets: %s", ld.ops.geterr(ld.if_h));
     }
   }
 
@@ -1809,14 +1809,14 @@
   {
     /* Get the capture statistics, and, if any packets were dropped, report
        that. */
-    if (pcap_stats(ld.pcap_h, &stats) >= 0) {
+    if (ld.ops.stats(ld.if_h, &stats) >= 0) {
       if (stats.ps_drop != 0) {
         fprintf(stderr, "%u packets dropped\n", stats.ps_drop);
       }
     } else {
-      cmdarg_err("Can't get packet-drop statistics: %s", pcap_geterr(ld.pcap_h));
+      cmdarg_err("Can't get packet-drop statistics: %s", ld.ops.geterr(ld.if_h));
     }
-    pcap_close(ld.pcap_h);
+    ld.ops.close(ld.if_h);
   }
 
   /* Report the number of captured packets if not reported during capture
@@ -1868,8 +1868,8 @@
   } else
 #endif
   {
-  if (ld.pcap_h != NULL)
-    pcap_close(ld.pcap_h);
+  if (ld.if_h != NULL)
+    ld.ops.close(ld.if_h);
   }
 
   return FALSE;
@@ -1947,7 +1947,7 @@
           fprintf(stderr, "\n");
         }
         show_capture_file_io_error(ld->save_file, err, FALSE);
-        pcap_close(ld->pcap_h);
+        ld->ops.close(ld->if_h);
         libpcap_dump_close(ld->pdh, &err);
         exit(2);
       }
Index: capture_loop.h
===================================================================
--- capture_loop.h	(revision 19257)
+++ capture_loop.h	(working copy)
@@ -114,7 +114,7 @@
   capture_packet_cb_fct  packet_cb;     /* callback for a single captured packet */
 
   /* pcap "input file" */
-  pcap_t        *pcap_h;                /* pcap handle */
+  void        *if_h;                  /* interface handle */
   gboolean       pcap_err;              /* E: TRUE if error from pcap */
 #ifdef MUST_DO_SELECT
   int            pcap_fd;               /* pcap file descriptor */
@@ -145,6 +145,8 @@
   gint           wtap_linktype;
   long           bytes_written;
 
+  /* PAOLO: added for usb support */
+  if_ops       ops;
 } loop_data;
 
 
@@ -156,8 +158,9 @@
   INITFILTER_OTHER_ERROR
 } initfilter_status_t;
 
+/* PAOLO: usb stuff need nore loop_data fields, so use whoole struct as args */
 extern initfilter_status_t
-capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter);
+capture_loop_init_filter(capture_options *capture_opts, loop_data* ld);
 
 #ifdef HAVE_LIBPCAP
 #ifndef _WIN32
Index: epan/dissectors/Makefile.common
===================================================================
--- epan/dissectors/Makefile.common	(revision 19257)
+++ epan/dissectors/Makefile.common	(working copy)
@@ -652,6 +652,7 @@
 	packet-uma.c	\
 	packet-udp.c	\
 	packet-ulp.c	\
+	packet-usb.c	\
 	packet-umts_fp.c	\
 	packet-umts_rrc.c	\
 	packet-umts_rrc_ies.c	\
Index: epan/dissectors/packet-usb.c
===================================================================
--- epan/dissectors/packet-usb.c	(revision 0)
+++ epan/dissectors/packet-usb.c	(revision 0)
@@ -0,0 +1,188 @@
+/* packet-usb.c
+ *
+ * $Id$
+ *
+ * usb basic dissector
+ * By Paolo Abeni <paolo.abeni@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+ 
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/etypes.h>
+#include <epan/addr_resolv.h>
+#include <epan/tap.h>
+
+#include <usb-structs.h>
+
+/* protocols and header fields */
+static int proto_usb = -1;
+static int hf_usb_urb_type = -1;
+static int hf_usb_device_address = -1;
+static int hf_usb_endpoint_number = -1;
+static int hf_usb_request_type = -1;
+static int hf_usb_request = -1;
+static int hf_usb_value = -1;
+static int hf_usb_index = -1;
+static int hf_usb_length = -1;
+static int hf_usb_data = -1;
+
+static gint usb_hdr = -1;
+static gint usb_setup_hdr = -1;
+
+static int usb_tap = -1;
+
+static const char* urb_type_string[] = {
+    "URB_CONTROL_INPUT",
+    "URB_CONTROL_OUTPUT",
+    "URB_ISOCHRONOUS_INPUT",
+    "URB_ISOCHRONOUS_OUTPUT",
+    "URB_INTERRUPT_INPUT",
+    "URB_INTERRUPT_OUTPUT",
+    "URB_BULK_INPUT",
+    "URB_BULK_OUTPUT"
+};
+
+static void
+dissect_usb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent)
+{
+    int offset = 0;
+    int type;
+    gboolean setup;
+    proto_tree *tree = 0;
+    
+    if (check_col(pinfo->cinfo, COL_PROTOCOL))
+        col_set_str(pinfo->cinfo, COL_PROTOCOL, "USB");
+
+    /* add usb hdr*/    
+    if (parent) {
+      proto_item *ti = proto_tree_add_protocol_format(parent, proto_usb, tvb, 0, 
+        sizeof(usb_header), "USB URB");
+
+      tree = proto_item_add_subtree(ti, usb_hdr);
+    }
+
+    
+    type = tvb_get_ntohl(tvb, offset);
+    proto_tree_add_string(tree, hf_usb_urb_type, tvb, offset, 4, 
+        urb_type_string[type]);
+    offset += 4;
+    proto_tree_add_item(tree, hf_usb_device_address, tvb, offset, 4, FALSE);
+    offset += 4;
+    proto_tree_add_item(tree, hf_usb_endpoint_number, tvb, offset, 4, FALSE);
+    offset += 4;
+    
+    /* check for setup hdr presence */
+    setup = tvb_get_ntohl(tvb, offset);
+    offset += 4;
+    if (setup)
+    {
+        proto_item *ti = proto_tree_add_protocol_format(parent, proto_usb, tvb, 
+            offset, sizeof(usb_setup), "URB setup");
+        
+        proto_tree* setup_tree = proto_item_add_subtree(ti, usb_setup_hdr);
+        
+        proto_tree_add_item(setup_tree, hf_usb_request_type, tvb, offset, 4, FALSE);
+        offset += 4;
+        proto_tree_add_item(setup_tree, hf_usb_request, tvb, offset, 4, FALSE);
+        offset += 4;
+        proto_tree_add_item(setup_tree, hf_usb_value, tvb, offset, 4, FALSE);
+        offset += 4;
+        proto_tree_add_item(setup_tree, hf_usb_index, tvb, offset, 4, FALSE);
+        offset += 4;
+        proto_tree_add_item(setup_tree, hf_usb_length, tvb, offset, 4, FALSE);
+        offset += 4;
+    }
+    
+    proto_tree_add_item(tree, hf_usb_data, tvb,
+        offset, tvb_length_remaining(tvb, offset), FALSE);
+    tap_queue_packet(usb_tap, pinfo, NULL);
+}
+
+
+void
+proto_register_usb(void)
+{
+    static hf_register_info hf[] = {
+    
+        { &hf_usb_urb_type,
+        { "URB type", "usb.urb_type", FT_STRING, BASE_NONE, NULL, 0x0,
+                "URB type", HFILL }},
+
+        { &hf_usb_device_address,
+        { "Device", "usb.device_address", FT_UINT32, BASE_DEC, NULL, 0x0,
+                "USB device address", HFILL }},
+
+        { &hf_usb_endpoint_number,
+        { "Endpoint", "usb.endpoint_number", FT_UINT32, BASE_DEC, NULL, 0x0,
+                "usb endpoint number", HFILL }},
+
+        { &hf_usb_request_type,
+        { "Request Type", "usb.request_type", FT_UINT32, BASE_HEX, NULL, 0x0,
+                "", HFILL }},
+
+        { &hf_usb_request,
+        { "Request", "usb.request", FT_UINT32, BASE_HEX, NULL, 0x0,
+                "", HFILL }},
+
+        { &hf_usb_value,
+        { "value", "usb.value", FT_UINT32, BASE_HEX, NULL, 0x0,
+                "", HFILL }},
+
+        { &hf_usb_index,
+        { "Index", "usb.index", FT_UINT32, BASE_DEC, NULL, 0x0,
+                "", HFILL }},
+
+        { &hf_usb_length,
+        { "Length", "usb.length", FT_UINT32, BASE_DEC, NULL, 0x0,
+                "", HFILL }},
+                
+        { &hf_usb_data,
+        {"Application Data", "usb.data",
+            FT_BYTES, BASE_HEX, NULL, 0x0,
+            "Payload is application data", HFILL }}
+    
+    };
+    
+    static gint *usb_subtrees[] = {
+            &usb_hdr,
+            &usb_setup_hdr
+    };
+
+     
+    proto_usb = proto_register_protocol("USB", "USB", "usb");
+    proto_register_field_array(proto_usb, hf, array_length(hf));
+    proto_register_subtree_array(usb_subtrees, array_length(usb_subtrees));
+
+    
+    register_dissector("eth", dissect_usb, proto_usb);
+    usb_tap = register_tap("usb");
+}
+
+void
+proto_reg_handoff_usb(void)
+{
+    dissector_handle_t usb_handle;
+    usb_handle = create_dissector_handle(dissect_usb, proto_usb);
+
+    dissector_add("wtap_encap", WTAP_ENCAP_USB, usb_handle);
+}
Index: capture_opts.c
===================================================================
--- capture_opts.c	(revision 19257)
+++ capture_opts.c	(working copy)
@@ -399,7 +399,7 @@
     data_link_info_t *data_link_info;
 
     /* Get the list of link-layer types for the capture device. */
-    lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
+    lt_list = get_linktype_list(capture_opts->iface, err_str);
     if (lt_list == NULL) {
       if (err_str[0] != '\0') {
         cmdarg_err("The list of data link types for the capture device \"%s\" could not be obtained (%s)."
Index: wiretap/wtap.h
===================================================================
--- wiretap/wtap.h	(revision 19257)
+++ wiretap/wtap.h	(working copy)
@@ -186,6 +186,10 @@
 /* last WTAP_ENCAP_ value + 1 */
 #define WTAP_NUM_ENCAP_TYPES			92
 
+/* PAOLO: alias for USB encap */
+#define WTAP_ENCAP_USB WTAP_ENCAP_USER0 
+
+
 /* File types that can be read by wiretap.
    We support writing some many of these file types, too, so we
    distinguish between different versions of them. */
Index: capture-usb.h
===================================================================
--- capture-usb.h	(revision 0)
+++ capture-usb.h	(revision 0)
@@ -0,0 +1,62 @@
+/* capture-usb.h
+ *
+ * $Id$
+ *
+ * USB sniffing API
+ * By Paolo Abeni <paolo.abeni@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+ 
+#ifndef __CAPTURE_USB_H__
+#define __CAPTURE_USB_H__
+
+#include <pcap.h>
+
+typedef struct pusb pusb_t;
+    
+extern int usb_fileno(pusb_t*);
+
+extern int usb_dispatch(pusb_t*, int, pcap_handler, u_char *user);
+
+extern pusb_t* usb_open_live(const char* bus, int snap, int promisc, int ms, 
+        char* errbuf);
+
+extern void usb_close(pusb_t*);
+
+extern int usb_snapshot(pusb_t*);
+
+extern int usb_stats(pusb_t *, struct pcap_stat *);
+
+extern char *usb_geterr(pusb_t *);
+
+extern GList *usb_find_all_devs(int *err, char *err_str);
+
+extern const char * usb_set_linktype(pusb_t *, char *, int);
+
+extern GList * usb_get_linktype_list(const char * name, char * );
+
+
+extern int usb_get_linktype(pusb_t *, const char*);
+
+extern int usb_setbuff(pusb_t *a, int b);
+
+extern int usb_compile(pusb_t *p, struct bpf_program *fp,
+               char *str, int optimize, bpf_u_int32 netmask);
+
+extern int usb_setfilter(pusb_t *p, struct bpf_program *fp);
+    
+extern void usb_breakloop(pusb_t* hnd);
+#endif