2005-04-16 15:20:36 -07:00
/*
* The USB Monitor , inspired by Dave Harding ' s USBMon .
*
* This is a text format reader .
*/
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/usb.h>
# include <linux/time.h>
2006-01-11 15:55:29 +01:00
# include <linux/mutex.h>
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
# include <linux/debugfs.h>
2009-11-06 12:32:23 -05:00
# include <linux/scatterlist.h>
2005-04-16 15:20:36 -07:00
# include <asm/uaccess.h>
# include "usb_mon.h"
/*
* No , we do not want arbitrarily long data strings .
* Use the binary interface if you want to capture bulk data !
*/
# define DATA_MAX 32
2005-06-25 14:32:59 -07:00
/*
* Defined by USB 2.0 clause 9.3 , table 9.2 .
*/
# define SETUP_MAX 8
2005-04-16 15:20:36 -07:00
/*
* This limit exists to prevent OOMs when the user process stops reading .
2006-06-09 20:10:10 -07:00
* If usbmon were available to unprivileged processes , it might be open
* to a local DoS . But we have to keep to root in order to prevent
* password sniffing from HID devices .
2005-04-16 15:20:36 -07:00
*/
2007-02-24 19:27:33 -08:00
# define EVENT_MAX (4*PAGE_SIZE / sizeof(struct mon_event_text))
2005-04-16 15:20:36 -07:00
2007-02-24 19:27:33 -08:00
/*
* Potentially unlimited number ; we limit it for similar allocations .
* The usbfs limits this to 128 , but we ' re not quite as generous .
*/
# define ISODESC_MAX 5
# define PRINTF_DFL 250 /* with 5 ISOs segs */
struct mon_iso_desc {
int status ;
unsigned int offset ;
unsigned int length ; /* Unsigned here, signed in URB. Historic. */
} ;
2005-04-16 15:20:36 -07:00
struct mon_event_text {
struct list_head e_link ;
int type ; /* submit, complete, etc. */
unsigned long id ; /* From pointer, most of the time */
unsigned int tstamp ;
2007-02-24 19:27:33 -08:00
int busnum ;
2007-08-14 00:33:40 -07:00
char devnum ;
char epnum ;
char is_in ;
char xfertype ;
2005-04-16 15:20:36 -07:00
int length ; /* Depends on type: xfer length or act length */
int status ;
2007-02-24 19:27:33 -08:00
int interval ;
int start_frame ;
int error_count ;
2005-06-25 14:32:59 -07:00
char setup_flag ;
2005-04-16 15:20:36 -07:00
char data_flag ;
2007-02-24 19:27:33 -08:00
int numdesc ; /* Full number */
struct mon_iso_desc isodesc [ ISODESC_MAX ] ;
2005-06-25 14:32:59 -07:00
unsigned char setup [ SETUP_MAX ] ;
2005-04-16 15:20:36 -07:00
unsigned char data [ DATA_MAX ] ;
} ;
# define SLAB_NAME_SZ 30
struct mon_reader_text {
2006-12-06 20:33:20 -08:00
struct kmem_cache * e_slab ;
2005-04-16 15:20:36 -07:00
int nevents ;
struct list_head e_list ;
struct mon_reader r ; /* In C, parent class can be placed anywhere */
wait_queue_head_t wait ;
int printf_size ;
char * printf_buf ;
2006-01-11 15:55:29 +01:00
struct mutex printf_lock ;
2005-04-16 15:20:36 -07:00
char slab_name [ SLAB_NAME_SZ ] ;
} ;
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
static struct dentry * mon_dir ; /* Usually /sys/kernel/debug/usbmon */
2008-07-25 19:45:34 -07:00
static void mon_text_ctor ( void * ) ;
2005-04-16 15:20:36 -07:00
2007-02-24 19:27:33 -08:00
struct mon_text_ptr {
int cnt , limit ;
char * pbuf ;
} ;
static struct mon_event_text *
mon_text_read_wait ( struct mon_reader_text * rp , struct file * file ) ;
static void mon_text_read_head_t ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep ) ;
static void mon_text_read_head_u ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep ) ;
static void mon_text_read_statset ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep ) ;
static void mon_text_read_intstat ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep ) ;
static void mon_text_read_isostat ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep ) ;
static void mon_text_read_isodesc ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep ) ;
static void mon_text_read_data ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep ) ;
2005-04-16 15:20:36 -07:00
/*
* mon_text_submit
* mon_text_complete
*
* May be called from an interrupt .
*
* This is called with the whole mon_bus locked , so no additional lock .
*/
2005-06-25 14:32:59 -07:00
static inline char mon_text_get_setup ( struct mon_event_text * ep ,
2006-08-30 11:35:21 -04:00
struct urb * urb , char ev_type , struct mon_bus * mbus )
2005-06-25 14:32:59 -07:00
{
2007-07-30 17:10:36 -04:00
if ( ep - > xfertype ! = USB_ENDPOINT_XFER_CONTROL | | ev_type ! = ' S ' )
2005-06-25 14:32:59 -07:00
return ' - ' ;
if ( urb - > setup_packet = = NULL )
return ' Z ' ; /* '0' would be not as pretty. */
memcpy ( ep - > setup , urb - > setup_packet , SETUP_MAX ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
static inline char mon_text_get_data ( struct mon_event_text * ep , struct urb * urb ,
2006-08-30 11:35:21 -04:00
int len , char ev_type , struct mon_bus * mbus )
2005-04-16 15:20:36 -07:00
{
2009-11-06 12:32:23 -05:00
void * src ;
2005-04-16 15:20:36 -07:00
if ( len < = 0 )
return ' L ' ;
2005-08-15 16:53:57 -07:00
if ( len > = DATA_MAX )
len = DATA_MAX ;
2005-04-16 15:20:36 -07:00
2007-07-30 17:10:36 -04:00
if ( ep - > is_in ) {
2007-02-24 19:27:33 -08:00
if ( ev_type ! = ' C ' )
2005-12-03 21:52:10 -08:00
return ' < ' ;
} else {
2007-02-24 19:27:33 -08:00
if ( ev_type ! = ' S ' )
2005-12-03 21:52:10 -08:00
return ' > ' ;
2005-04-16 15:20:36 -07:00
}
2009-11-06 12:32:23 -05:00
if ( urb - > num_sgs = = 0 ) {
src = urb - > transfer_buffer ;
if ( src = = NULL )
return ' Z ' ; /* '0' would be not as pretty. */
} else {
struct scatterlist * sg = urb - > sg - > sg ;
/* If IOMMU coalescing occurred, we cannot trust sg_page */
if ( urb - > sg - > nents ! = urb - > num_sgs | |
PageHighMem ( sg_page ( sg ) ) )
return ' D ' ;
/* For the text interface we copy only the first sg buffer */
len = min_t ( int , sg - > length , len ) ;
src = sg_virt ( sg ) ;
}
2005-08-15 16:53:57 -07:00
2009-11-06 12:32:23 -05:00
memcpy ( ep - > data , src , len ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
static inline unsigned int mon_get_timestamp ( void )
{
struct timeval tval ;
unsigned int stamp ;
do_gettimeofday ( & tval ) ;
stamp = tval . tv_sec & 0xFFFF ; /* 2^32 = 4294967296. Limit to 4096s. */
stamp = stamp * 1000000 + tval . tv_usec ;
return stamp ;
}
static void mon_text_event ( struct mon_reader_text * rp , struct urb * urb ,
2007-08-24 15:41:41 -04:00
char ev_type , int status )
2005-04-16 15:20:36 -07:00
{
struct mon_event_text * ep ;
unsigned int stamp ;
2007-02-24 19:27:33 -08:00
struct usb_iso_packet_descriptor * fp ;
struct mon_iso_desc * dp ;
int i , ndesc ;
2005-04-16 15:20:36 -07:00
stamp = mon_get_timestamp ( ) ;
if ( rp - > nevents > = EVENT_MAX | |
2006-12-06 20:33:16 -08:00
( ep = kmem_cache_alloc ( rp - > e_slab , GFP_ATOMIC ) ) = = NULL ) {
2005-04-16 15:20:36 -07:00
rp - > r . m_bus - > cnt_text_lost + + ;
return ;
}
ep - > type = ev_type ;
ep - > id = ( unsigned long ) urb ;
2007-04-11 13:47:26 -07:00
ep - > busnum = urb - > dev - > bus - > busnum ;
2007-07-30 17:10:36 -04:00
ep - > devnum = urb - > dev - > devnum ;
ep - > epnum = usb_endpoint_num ( & urb - > ep - > desc ) ;
ep - > xfertype = usb_endpoint_type ( & urb - > ep - > desc ) ;
ep - > is_in = usb_urb_dir_in ( urb ) ;
2005-04-16 15:20:36 -07:00
ep - > tstamp = stamp ;
ep - > length = ( ev_type = = ' S ' ) ?
urb - > transfer_buffer_length : urb - > actual_length ;
/* Collecting status makes debugging sense for submits, too */
2007-08-24 15:41:41 -04:00
ep - > status = status ;
2005-04-16 15:20:36 -07:00
2007-07-30 17:10:36 -04:00
if ( ep - > xfertype = = USB_ENDPOINT_XFER_INT ) {
2007-02-24 19:27:33 -08:00
ep - > interval = urb - > interval ;
2007-07-30 17:10:36 -04:00
} else if ( ep - > xfertype = = USB_ENDPOINT_XFER_ISOC ) {
2007-02-24 19:27:33 -08:00
ep - > interval = urb - > interval ;
ep - > start_frame = urb - > start_frame ;
ep - > error_count = urb - > error_count ;
}
ep - > numdesc = urb - > number_of_packets ;
2007-07-30 17:10:36 -04:00
if ( ep - > xfertype = = USB_ENDPOINT_XFER_ISOC & &
urb - > number_of_packets > 0 ) {
2007-02-24 19:27:33 -08:00
if ( ( ndesc = urb - > number_of_packets ) > ISODESC_MAX )
ndesc = ISODESC_MAX ;
fp = urb - > iso_frame_desc ;
dp = ep - > isodesc ;
for ( i = 0 ; i < ndesc ; i + + ) {
dp - > status = fp - > status ;
dp - > offset = fp - > offset ;
dp - > length = ( ev_type = = ' S ' ) ?
fp - > length : fp - > actual_length ;
fp + + ;
dp + + ;
}
}
2006-08-30 11:35:21 -04:00
ep - > setup_flag = mon_text_get_setup ( ep , urb , ev_type , rp - > r . m_bus ) ;
ep - > data_flag = mon_text_get_data ( ep , urb , ep - > length , ev_type ,
rp - > r . m_bus ) ;
2005-04-16 15:20:36 -07:00
rp - > nevents + + ;
list_add_tail ( & ep - > e_link , & rp - > e_list ) ;
wake_up ( & rp - > wait ) ;
}
static void mon_text_submit ( void * data , struct urb * urb )
{
struct mon_reader_text * rp = data ;
2007-08-24 15:41:41 -04:00
mon_text_event ( rp , urb , ' S ' , - EINPROGRESS ) ;
2005-04-16 15:20:36 -07:00
}
2007-08-24 15:41:41 -04:00
static void mon_text_complete ( void * data , struct urb * urb , int status )
2005-04-16 15:20:36 -07:00
{
struct mon_reader_text * rp = data ;
2007-08-24 15:41:41 -04:00
mon_text_event ( rp , urb , ' C ' , status ) ;
2005-04-16 15:20:36 -07:00
}
2006-06-09 22:03:32 -07:00
static void mon_text_error ( void * data , struct urb * urb , int error )
{
struct mon_reader_text * rp = data ;
struct mon_event_text * ep ;
if ( rp - > nevents > = EVENT_MAX | |
2006-12-06 20:33:16 -08:00
( ep = kmem_cache_alloc ( rp - > e_slab , GFP_ATOMIC ) ) = = NULL ) {
2006-06-09 22:03:32 -07:00
rp - > r . m_bus - > cnt_text_lost + + ;
return ;
}
ep - > type = ' E ' ;
ep - > id = ( unsigned long ) urb ;
2007-02-24 19:27:33 -08:00
ep - > busnum = 0 ;
2007-07-30 17:10:36 -04:00
ep - > devnum = urb - > dev - > devnum ;
ep - > epnum = usb_endpoint_num ( & urb - > ep - > desc ) ;
ep - > xfertype = usb_endpoint_type ( & urb - > ep - > desc ) ;
ep - > is_in = usb_urb_dir_in ( urb ) ;
2006-06-09 22:03:32 -07:00
ep - > tstamp = 0 ;
ep - > length = 0 ;
ep - > status = error ;
ep - > setup_flag = ' - ' ;
ep - > data_flag = ' E ' ;
rp - > nevents + + ;
list_add_tail ( & ep - > e_link , & rp - > e_list ) ;
wake_up ( & rp - > wait ) ;
}
2005-04-16 15:20:36 -07:00
/*
* Fetch next event from the circular buffer .
*/
static struct mon_event_text * mon_text_fetch ( struct mon_reader_text * rp ,
struct mon_bus * mbus )
{
struct list_head * p ;
unsigned long flags ;
spin_lock_irqsave ( & mbus - > lock , flags ) ;
if ( list_empty ( & rp - > e_list ) ) {
spin_unlock_irqrestore ( & mbus - > lock , flags ) ;
return NULL ;
}
p = rp - > e_list . next ;
list_del ( p ) ;
- - rp - > nevents ;
spin_unlock_irqrestore ( & mbus - > lock , flags ) ;
return list_entry ( p , struct mon_event_text , e_link ) ;
}
/*
*/
static int mon_text_open ( struct inode * inode , struct file * file )
{
struct mon_bus * mbus ;
struct mon_reader_text * rp ;
int rc ;
2006-01-11 15:55:29 +01:00
mutex_lock ( & mon_lock ) ;
2006-09-27 01:50:46 -07:00
mbus = inode - > i_private ;
2005-04-16 15:20:36 -07:00
2006-02-27 21:29:43 +01:00
rp = kzalloc ( sizeof ( struct mon_reader_text ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( rp = = NULL ) {
rc = - ENOMEM ;
goto err_alloc ;
}
INIT_LIST_HEAD ( & rp - > e_list ) ;
init_waitqueue_head ( & rp - > wait ) ;
2006-01-11 15:55:29 +01:00
mutex_init ( & rp - > printf_lock ) ;
2005-04-16 15:20:36 -07:00
rp - > printf_size = PRINTF_DFL ;
rp - > printf_buf = kmalloc ( rp - > printf_size , GFP_KERNEL ) ;
if ( rp - > printf_buf = = NULL ) {
rc = - ENOMEM ;
goto err_alloc_pr ;
}
rp - > r . m_bus = mbus ;
rp - > r . r_data = rp ;
rp - > r . rnf_submit = mon_text_submit ;
2006-06-09 22:03:32 -07:00
rp - > r . rnf_error = mon_text_error ;
2005-04-16 15:20:36 -07:00
rp - > r . rnf_complete = mon_text_complete ;
2007-04-11 13:47:26 -07:00
snprintf ( rp - > slab_name , SLAB_NAME_SZ , " mon_text_%p " , rp ) ;
2005-04-16 15:20:36 -07:00
rp - > e_slab = kmem_cache_create ( rp - > slab_name ,
sizeof ( struct mon_event_text ) , sizeof ( long ) , 0 ,
2007-07-20 10:11:58 +09:00
mon_text_ctor ) ;
2005-04-16 15:20:36 -07:00
if ( rp - > e_slab = = NULL ) {
rc = - ENOMEM ;
goto err_slab ;
}
mon_reader_add ( mbus , & rp - > r ) ;
file - > private_data = rp ;
2006-01-11 15:55:29 +01:00
mutex_unlock ( & mon_lock ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
// err_busy:
// kmem_cache_destroy(rp->e_slab);
err_slab :
kfree ( rp - > printf_buf ) ;
err_alloc_pr :
kfree ( rp ) ;
err_alloc :
2006-01-11 15:55:29 +01:00
mutex_unlock ( & mon_lock ) ;
2005-04-16 15:20:36 -07:00
return rc ;
}
/*
* For simplicity , we read one record in one system call and throw out
* what does not fit . This means that the following does not work :
* dd if = / dbg / usbmon / 0 t bs = 10
* Also , we do not allow seeks and do not bother advancing the offset .
*/
2007-02-24 19:27:33 -08:00
static ssize_t mon_text_read_t ( struct file * file , char __user * buf ,
size_t nbytes , loff_t * ppos )
{
struct mon_reader_text * rp = file - > private_data ;
struct mon_event_text * ep ;
struct mon_text_ptr ptr ;
if ( IS_ERR ( ep = mon_text_read_wait ( rp , file ) ) )
return PTR_ERR ( ep ) ;
mutex_lock ( & rp - > printf_lock ) ;
ptr . cnt = 0 ;
ptr . pbuf = rp - > printf_buf ;
ptr . limit = rp - > printf_size ;
mon_text_read_head_t ( rp , & ptr , ep ) ;
mon_text_read_statset ( rp , & ptr , ep ) ;
ptr . cnt + = snprintf ( ptr . pbuf + ptr . cnt , ptr . limit - ptr . cnt ,
" %d " , ep - > length ) ;
mon_text_read_data ( rp , & ptr , ep ) ;
if ( copy_to_user ( buf , rp - > printf_buf , ptr . cnt ) )
ptr . cnt = - EFAULT ;
mutex_unlock ( & rp - > printf_lock ) ;
kmem_cache_free ( rp - > e_slab , ep ) ;
return ptr . cnt ;
}
static ssize_t mon_text_read_u ( struct file * file , char __user * buf ,
2005-04-16 15:20:36 -07:00
size_t nbytes , loff_t * ppos )
{
struct mon_reader_text * rp = file - > private_data ;
2007-02-24 19:27:33 -08:00
struct mon_event_text * ep ;
struct mon_text_ptr ptr ;
if ( IS_ERR ( ep = mon_text_read_wait ( rp , file ) ) )
return PTR_ERR ( ep ) ;
mutex_lock ( & rp - > printf_lock ) ;
ptr . cnt = 0 ;
ptr . pbuf = rp - > printf_buf ;
ptr . limit = rp - > printf_size ;
mon_text_read_head_u ( rp , & ptr , ep ) ;
if ( ep - > type = = ' E ' ) {
mon_text_read_statset ( rp , & ptr , ep ) ;
2007-07-30 17:10:36 -04:00
} else if ( ep - > xfertype = = USB_ENDPOINT_XFER_ISOC ) {
2007-02-24 19:27:33 -08:00
mon_text_read_isostat ( rp , & ptr , ep ) ;
mon_text_read_isodesc ( rp , & ptr , ep ) ;
2007-07-30 17:10:36 -04:00
} else if ( ep - > xfertype = = USB_ENDPOINT_XFER_INT ) {
2007-02-24 19:27:33 -08:00
mon_text_read_intstat ( rp , & ptr , ep ) ;
} else {
mon_text_read_statset ( rp , & ptr , ep ) ;
}
ptr . cnt + = snprintf ( ptr . pbuf + ptr . cnt , ptr . limit - ptr . cnt ,
" %d " , ep - > length ) ;
mon_text_read_data ( rp , & ptr , ep ) ;
if ( copy_to_user ( buf , rp - > printf_buf , ptr . cnt ) )
ptr . cnt = - EFAULT ;
mutex_unlock ( & rp - > printf_lock ) ;
kmem_cache_free ( rp - > e_slab , ep ) ;
return ptr . cnt ;
}
static struct mon_event_text * mon_text_read_wait ( struct mon_reader_text * rp ,
struct file * file )
{
2005-04-16 15:20:36 -07:00
struct mon_bus * mbus = rp - > r . m_bus ;
DECLARE_WAITQUEUE ( waita , current ) ;
struct mon_event_text * ep ;
add_wait_queue ( & rp - > wait , & waita ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
while ( ( ep = mon_text_fetch ( rp , mbus ) ) = = NULL ) {
if ( file - > f_flags & O_NONBLOCK ) {
set_current_state ( TASK_RUNNING ) ;
remove_wait_queue ( & rp - > wait , & waita ) ;
2007-02-24 19:27:33 -08:00
return ERR_PTR ( - EWOULDBLOCK ) ;
2005-04-16 15:20:36 -07:00
}
/*
* We do not count nwaiters , because - > release is supposed
* to be called when all openers are gone only .
*/
schedule ( ) ;
if ( signal_pending ( current ) ) {
remove_wait_queue ( & rp - > wait , & waita ) ;
2007-02-24 19:27:33 -08:00
return ERR_PTR ( - EINTR ) ;
2005-04-16 15:20:36 -07:00
}
set_current_state ( TASK_INTERRUPTIBLE ) ;
}
set_current_state ( TASK_RUNNING ) ;
remove_wait_queue ( & rp - > wait , & waita ) ;
2007-02-24 19:27:33 -08:00
return ep ;
}
2005-04-16 15:20:36 -07:00
2007-02-24 19:27:33 -08:00
static void mon_text_read_head_t ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep )
{
char udir , utype ;
2005-04-16 15:20:36 -07:00
2007-07-30 17:10:36 -04:00
udir = ( ep - > is_in ? ' i ' : ' o ' ) ;
switch ( ep - > xfertype ) {
case USB_ENDPOINT_XFER_ISOC : utype = ' Z ' ; break ;
case USB_ENDPOINT_XFER_INT : utype = ' I ' ; break ;
case USB_ENDPOINT_XFER_CONTROL : utype = ' C ' ; break ;
2005-04-16 15:20:36 -07:00
default : /* PIPE_BULK */ utype = ' B ' ;
}
2007-02-24 19:27:33 -08:00
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
2005-06-25 14:32:59 -07:00
" %lx %u %c %c%c:%03u:%02u " ,
2005-04-16 15:20:36 -07:00
ep - > id , ep - > tstamp , ep - > type ,
2007-07-30 17:10:36 -04:00
utype , udir , ep - > devnum , ep - > epnum ) ;
2007-02-24 19:27:33 -08:00
}
static void mon_text_read_head_u ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep )
{
char udir , utype ;
2007-07-30 17:10:36 -04:00
udir = ( ep - > is_in ? ' i ' : ' o ' ) ;
switch ( ep - > xfertype ) {
case USB_ENDPOINT_XFER_ISOC : utype = ' Z ' ; break ;
case USB_ENDPOINT_XFER_INT : utype = ' I ' ; break ;
case USB_ENDPOINT_XFER_CONTROL : utype = ' C ' ; break ;
2007-02-24 19:27:33 -08:00
default : /* PIPE_BULK */ utype = ' B ' ;
}
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
" %lx %u %c %c%c:%d:%03u:%u " ,
ep - > id , ep - > tstamp , ep - > type ,
2007-07-30 17:10:36 -04:00
utype , udir , ep - > busnum , ep - > devnum , ep - > epnum ) ;
2007-02-24 19:27:33 -08:00
}
static void mon_text_read_statset ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep )
{
2005-06-25 14:32:59 -07:00
if ( ep - > setup_flag = = 0 ) { /* Setup packet is present and captured */
2007-02-24 19:27:33 -08:00
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
2005-06-25 14:32:59 -07:00
" s %02x %02x %04x %04x %04x " ,
ep - > setup [ 0 ] ,
ep - > setup [ 1 ] ,
( ep - > setup [ 3 ] < < 8 ) | ep - > setup [ 2 ] ,
( ep - > setup [ 5 ] < < 8 ) | ep - > setup [ 4 ] ,
( ep - > setup [ 7 ] < < 8 ) | ep - > setup [ 6 ] ) ;
} else if ( ep - > setup_flag ! = ' - ' ) { /* Unable to capture setup packet */
2007-02-24 19:27:33 -08:00
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
2005-06-25 14:32:59 -07:00
" %c __ __ ____ ____ ____ " , ep - > setup_flag ) ;
} else { /* No setup for this kind of URB */
2007-02-24 19:27:33 -08:00
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
" %d " , ep - > status ) ;
}
}
static void mon_text_read_intstat ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep )
{
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
" %d:%d " , ep - > status , ep - > interval ) ;
}
static void mon_text_read_isostat ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep )
{
if ( ep - > type = = ' S ' ) {
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
" %d:%d:%d " , ep - > status , ep - > interval , ep - > start_frame ) ;
} else {
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
" %d:%d:%d:%d " ,
ep - > status , ep - > interval , ep - > start_frame , ep - > error_count ) ;
2005-06-25 14:32:59 -07:00
}
2007-02-24 19:27:33 -08:00
}
static void mon_text_read_isodesc ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep )
{
int ndesc ; /* Display this many */
int i ;
const struct mon_iso_desc * dp ;
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
" %d " , ep - > numdesc ) ;
ndesc = ep - > numdesc ;
if ( ndesc > ISODESC_MAX )
ndesc = ISODESC_MAX ;
if ( ndesc < 0 )
ndesc = 0 ;
dp = ep - > isodesc ;
for ( i = 0 ; i < ndesc ; i + + ) {
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
" %d:%u:%u " , dp - > status , dp - > offset , dp - > length ) ;
dp + + ;
}
}
static void mon_text_read_data ( struct mon_reader_text * rp ,
struct mon_text_ptr * p , const struct mon_event_text * ep )
{
int data_len , i ;
2005-04-16 15:20:36 -07:00
if ( ( data_len = ep - > length ) > 0 ) {
if ( ep - > data_flag = = 0 ) {
2007-02-24 19:27:33 -08:00
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
" = " ) ;
2005-04-16 15:20:36 -07:00
if ( data_len > = DATA_MAX )
data_len = DATA_MAX ;
for ( i = 0 ; i < data_len ; i + + ) {
if ( i % 4 = = 0 ) {
2007-02-24 19:27:33 -08:00
p - > cnt + = snprintf ( p - > pbuf + p - > cnt ,
p - > limit - p - > cnt ,
2005-04-16 15:20:36 -07:00
" " ) ;
}
2007-02-24 19:27:33 -08:00
p - > cnt + = snprintf ( p - > pbuf + p - > cnt ,
p - > limit - p - > cnt ,
2005-04-16 15:20:36 -07:00
" %02x " , ep - > data [ i ] ) ;
}
2007-02-24 19:27:33 -08:00
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
" \n " ) ;
2005-04-16 15:20:36 -07:00
} else {
2007-02-24 19:27:33 -08:00
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt ,
2005-04-16 15:20:36 -07:00
" %c \n " , ep - > data_flag ) ;
}
} else {
2007-02-24 19:27:33 -08:00
p - > cnt + = snprintf ( p - > pbuf + p - > cnt , p - > limit - p - > cnt , " \n " ) ;
2005-04-16 15:20:36 -07:00
}
}
static int mon_text_release ( struct inode * inode , struct file * file )
{
struct mon_reader_text * rp = file - > private_data ;
struct mon_bus * mbus ;
/* unsigned long flags; */
struct list_head * p ;
struct mon_event_text * ep ;
2006-01-11 15:55:29 +01:00
mutex_lock ( & mon_lock ) ;
2006-09-27 01:50:46 -07:00
mbus = inode - > i_private ;
2005-04-16 15:20:36 -07:00
if ( mbus - > nreaders < = 0 ) {
printk ( KERN_ERR TAG " : consistency error on close \n " ) ;
2006-01-11 15:55:29 +01:00
mutex_unlock ( & mon_lock ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
mon_reader_del ( mbus , & rp - > r ) ;
/*
* In theory , e_list is protected by mbus - > lock . However ,
* after mon_reader_del has finished , the following is the case :
* - we are not on reader list anymore , so new events won ' t be added ;
* - whole mbus may be dropped if it was orphaned .
* So , we better not touch mbus .
*/
/* spin_lock_irqsave(&mbus->lock, flags); */
while ( ! list_empty ( & rp - > e_list ) ) {
p = rp - > e_list . next ;
ep = list_entry ( p , struct mon_event_text , e_link ) ;
list_del ( p ) ;
- - rp - > nevents ;
kmem_cache_free ( rp - > e_slab , ep ) ;
}
/* spin_unlock_irqrestore(&mbus->lock, flags); */
kmem_cache_destroy ( rp - > e_slab ) ;
kfree ( rp - > printf_buf ) ;
kfree ( rp ) ;
2006-01-11 15:55:29 +01:00
mutex_unlock ( & mon_lock ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-02-24 19:27:33 -08:00
static const struct file_operations mon_fops_text_t = {
2005-04-16 15:20:36 -07:00
. owner = THIS_MODULE ,
. open = mon_text_open ,
. llseek = no_llseek ,
2007-02-24 19:27:33 -08:00
. read = mon_text_read_t ,
. release = mon_text_release ,
} ;
static const struct file_operations mon_fops_text_u = {
. owner = THIS_MODULE ,
. open = mon_text_open ,
. llseek = no_llseek ,
. read = mon_text_read_u ,
2005-04-16 15:20:36 -07:00
. release = mon_text_release ,
} ;
2007-05-03 16:51:16 -07:00
int mon_text_add ( struct mon_bus * mbus , const struct usb_bus * ubus )
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
{
struct dentry * d ;
enum { NAMESZ = 10 } ;
char name [ NAMESZ ] ;
2007-05-03 16:51:16 -07:00
int busnum = ubus ? ubus - > busnum : 0 ;
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
int rc ;
2007-05-03 16:51:16 -07:00
if ( ubus ! = NULL ) {
rc = snprintf ( name , NAMESZ , " %dt " , busnum ) ;
if ( rc < = 0 | | rc > = NAMESZ )
goto err_print_t ;
d = debugfs_create_file ( name , 0600 , mon_dir , mbus ,
& mon_fops_text_t ) ;
if ( d = = NULL )
goto err_create_t ;
mbus - > dent_t = d ;
}
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
2007-04-11 13:47:26 -07:00
rc = snprintf ( name , NAMESZ , " %du " , busnum ) ;
2007-02-24 19:27:33 -08:00
if ( rc < = 0 | | rc > = NAMESZ )
goto err_print_u ;
d = debugfs_create_file ( name , 0600 , mon_dir , mbus , & mon_fops_text_u ) ;
if ( d = = NULL )
goto err_create_u ;
mbus - > dent_u = d ;
2007-04-11 13:47:26 -07:00
rc = snprintf ( name , NAMESZ , " %ds " , busnum ) ;
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
if ( rc < = 0 | | rc > = NAMESZ )
goto err_print_s ;
d = debugfs_create_file ( name , 0600 , mon_dir , mbus , & mon_fops_stat ) ;
if ( d = = NULL )
goto err_create_s ;
mbus - > dent_s = d ;
return 1 ;
err_create_s :
err_print_s :
2007-02-24 19:27:33 -08:00
debugfs_remove ( mbus - > dent_u ) ;
mbus - > dent_u = NULL ;
err_create_u :
err_print_u :
2007-05-03 16:51:16 -07:00
if ( ubus ! = NULL ) {
debugfs_remove ( mbus - > dent_t ) ;
mbus - > dent_t = NULL ;
}
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
err_create_t :
err_print_t :
return 0 ;
}
void mon_text_del ( struct mon_bus * mbus )
{
2007-02-24 19:27:33 -08:00
debugfs_remove ( mbus - > dent_u ) ;
2007-05-03 16:51:16 -07:00
if ( mbus - > dent_t ! = NULL )
debugfs_remove ( mbus - > dent_t ) ;
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
debugfs_remove ( mbus - > dent_s ) ;
}
2005-04-16 15:20:36 -07:00
/*
* Slab interface : constructor .
*/
2008-07-25 19:45:34 -07:00
static void mon_text_ctor ( void * mem )
2005-04-16 15:20:36 -07:00
{
/*
* Nothing to initialize . No , really !
* So , we fill it with garbage to emulate a reused object .
*/
memset ( mem , 0xe5 , sizeof ( struct mon_event_text ) ) ;
}
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
int __init mon_text_init ( void )
{
struct dentry * mondir ;
2009-04-24 15:15:49 -07:00
mondir = debugfs_create_dir ( " usbmon " , usb_debug_root ) ;
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
if ( IS_ERR ( mondir ) ) {
printk ( KERN_NOTICE TAG " : debugfs is not available \n " ) ;
return - ENODEV ;
}
if ( mondir = = NULL ) {
printk ( KERN_NOTICE TAG " : unable to create usbmon directory \n " ) ;
return - ENODEV ;
}
mon_dir = mondir ;
return 0 ;
}
2007-02-20 10:37:52 -08:00
void mon_text_exit ( void )
USB: add binary API to usbmon
This patch adds a new, "binary" API in addition to the old, text API usbmon
had before. The new API allows for less CPU use, and it allows to capture
all data from a packet where old API only captured 32 bytes at most. There
are some limitations and conditions to this, e.g. in case someone constructs
a URB with 1GB of data, it's not likely to be captured, because even the
huge buffers of the new reader are finite. Nonetheless, I expect this new
capability to capture all data for all real life scenarios.
The downside is, a special user mode application is required where cat(1)
worked before. I have sample code at http://people.redhat.com/zaitcev/linux/
and Paolo Abeni is working on patching libpcap.
This patch was initially written by Paolo and later I tweaked it, and
we had a little back-and-forth. So this is a jointly authored patch, but
I am submitting this I am responsible for the bugs.
Signed-off-by: Paolo Abeni <paolo.abeni@email.it>
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-12-30 22:43:10 -08:00
{
debugfs_remove ( mon_dir ) ;
}