pcap-usb-linux.c revision 235426
1190214Srpaulo/* 2190214Srpaulo * Copyright (c) 2006 Paolo Abeni (Italy) 3190214Srpaulo * All rights reserved. 4190214Srpaulo * 5190214Srpaulo * Redistribution and use in source and binary forms, with or without 6190214Srpaulo * modification, are permitted provided that the following conditions 7190214Srpaulo * are met: 8190214Srpaulo * 9190214Srpaulo * 1. Redistributions of source code must retain the above copyright 10190214Srpaulo * notice, this list of conditions and the following disclaimer. 11190214Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 12190214Srpaulo * notice, this list of conditions and the following disclaimer in the 13190214Srpaulo * documentation and/or other materials provided with the distribution. 14190214Srpaulo * 3. The name of the author may not be used to endorse or promote 15190214Srpaulo * products derived from this software without specific prior written 16190214Srpaulo * permission. 17190214Srpaulo * 18190214Srpaulo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19190214Srpaulo * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20190214Srpaulo * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21190214Srpaulo * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22190214Srpaulo * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23190214Srpaulo * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24190214Srpaulo * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25190214Srpaulo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26190214Srpaulo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27190214Srpaulo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28190214Srpaulo * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29190214Srpaulo * 30190214Srpaulo * USB sniffing API implementation for Linux platform 31190214Srpaulo * By Paolo Abeni <paolo.abeni@email.it> 32190214Srpaulo * Modifications: Kris Katterjohn <katterjohn@gmail.com> 33190214Srpaulo * 34190214Srpaulo */ 35190214Srpaulo#ifndef lint 36190214Srpaulostatic const char rcsid[] _U_ = 37214518Srpaulo "@(#) $Header: /tcpdump/master/libpcap/pcap-usb-linux.c,v 1.33 2008-12-23 21:38:50 guy Exp $ (LBL)"; 38190214Srpaulo#endif 39190214Srpaulo 40190214Srpaulo#ifdef HAVE_CONFIG_H 41190214Srpaulo#include "config.h" 42190214Srpaulo#endif 43190214Srpaulo 44190214Srpaulo#include "pcap-int.h" 45190214Srpaulo#include "pcap-usb-linux.h" 46190214Srpaulo#include "pcap/usb.h" 47190214Srpaulo 48190214Srpaulo#ifdef NEED_STRERROR_H 49190214Srpaulo#include "strerror.h" 50190214Srpaulo#endif 51190214Srpaulo 52190214Srpaulo#include <ctype.h> 53190214Srpaulo#include <errno.h> 54190214Srpaulo#include <stdlib.h> 55190214Srpaulo#include <unistd.h> 56190214Srpaulo#include <fcntl.h> 57190214Srpaulo#include <string.h> 58190214Srpaulo#include <dirent.h> 59190214Srpaulo#include <byteswap.h> 60190214Srpaulo#include <netinet/in.h> 61190214Srpaulo#include <sys/ioctl.h> 62190214Srpaulo#include <sys/mman.h> 63214518Srpaulo#ifdef HAVE_LINUX_USBDEVICE_FS_H 64235426Sdelphij/* 65235426Sdelphij * We might need <linux/compiler.h> to define __user for 66235426Sdelphij * <linux/usbdevice_fs.h>. 67235426Sdelphij */ 68235426Sdelphij#ifdef HAVE_LINUX_COMPILER_H 69235426Sdelphij#include <linux/compiler.h> 70235426Sdelphij#endif /* HAVE_LINUX_COMPILER_H */ 71214518Srpaulo#include <linux/usbdevice_fs.h> 72235426Sdelphij#endif /* HAVE_LINUX_USBDEVICE_FS_H */ 73190214Srpaulo 74214518Srpaulo#define USB_IFACE "usbmon" 75214518Srpaulo#define USB_TEXT_DIR_OLD "/sys/kernel/debug/usbmon" 76214518Srpaulo#define USB_TEXT_DIR "/sys/kernel/debug/usb/usbmon" 77214518Srpaulo#define SYS_USB_BUS_DIR "/sys/bus/usb/devices" 78214518Srpaulo#define PROC_USB_BUS_DIR "/proc/bus/usb" 79190214Srpaulo#define USB_LINE_LEN 4096 80190214Srpaulo 81190214Srpaulo#if __BYTE_ORDER == __LITTLE_ENDIAN 82190214Srpaulo#define htols(s) s 83190214Srpaulo#define htoll(l) l 84190214Srpaulo#define htol64(ll) ll 85190214Srpaulo#else 86190214Srpaulo#define htols(s) bswap_16(s) 87190214Srpaulo#define htoll(l) bswap_32(l) 88190214Srpaulo#define htol64(ll) bswap_64(ll) 89190214Srpaulo#endif 90190214Srpaulo 91190214Srpaulostruct mon_bin_stats { 92190214Srpaulo u_int32_t queued; 93190214Srpaulo u_int32_t dropped; 94190214Srpaulo}; 95190214Srpaulo 96190214Srpaulostruct mon_bin_get { 97190214Srpaulo pcap_usb_header *hdr; 98190214Srpaulo void *data; 99190214Srpaulo size_t data_len; /* Length of data (can be zero) */ 100190214Srpaulo}; 101190214Srpaulo 102190214Srpaulostruct mon_bin_mfetch { 103190214Srpaulo int32_t *offvec; /* Vector of events fetched */ 104190214Srpaulo int32_t nfetch; /* Number of events to fetch (out: fetched) */ 105190214Srpaulo int32_t nflush; /* Number of events to flush */ 106190214Srpaulo}; 107190214Srpaulo 108190214Srpaulo#define MON_IOC_MAGIC 0x92 109190214Srpaulo 110190214Srpaulo#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1) 111190214Srpaulo#define MON_IOCX_URB _IOWR(MON_IOC_MAGIC, 2, struct mon_bin_hdr) 112190214Srpaulo#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) 113190214Srpaulo#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4) 114190214Srpaulo#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5) 115190214Srpaulo#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) 116190214Srpaulo#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) 117190214Srpaulo#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) 118190214Srpaulo 119190214Srpaulo#define MON_BIN_SETUP 0x1 /* setup hdr is present*/ 120190214Srpaulo#define MON_BIN_SETUP_ZERO 0x2 /* setup buffer is not available */ 121190214Srpaulo#define MON_BIN_DATA_ZERO 0x4 /* data buffer is not available */ 122190214Srpaulo#define MON_BIN_ERROR 0x8 123190214Srpaulo 124190214Srpaulo/* forward declaration */ 125190214Srpaulostatic int usb_activate(pcap_t *); 126190214Srpaulostatic int usb_stats_linux(pcap_t *, struct pcap_stat *); 127190214Srpaulostatic int usb_stats_linux_bin(pcap_t *, struct pcap_stat *); 128190214Srpaulostatic int usb_read_linux(pcap_t *, int , pcap_handler , u_char *); 129190214Srpaulostatic int usb_read_linux_bin(pcap_t *, int , pcap_handler , u_char *); 130190214Srpaulostatic int usb_read_linux_mmap(pcap_t *, int , pcap_handler , u_char *); 131190214Srpaulostatic int usb_inject_linux(pcap_t *, const void *, size_t); 132190214Srpaulostatic int usb_setdirection_linux(pcap_t *, pcap_direction_t); 133190214Srpaulostatic void usb_cleanup_linux_mmap(pcap_t *); 134190214Srpaulo 135190214Srpaulo/* facility to add an USB device to the device list*/ 136190214Srpaulostatic int 137190214Srpaulousb_dev_add(pcap_if_t** alldevsp, int n, char *err_str) 138190214Srpaulo{ 139190214Srpaulo char dev_name[10]; 140190214Srpaulo char dev_descr[30]; 141190214Srpaulo snprintf(dev_name, 10, USB_IFACE"%d", n); 142190214Srpaulo snprintf(dev_descr, 30, "USB bus number %d", n); 143190214Srpaulo 144190214Srpaulo if (pcap_add_if(alldevsp, dev_name, 0, 145190214Srpaulo dev_descr, err_str) < 0) 146190214Srpaulo return -1; 147190214Srpaulo return 0; 148190214Srpaulo} 149190214Srpaulo 150190214Srpauloint 151190214Srpaulousb_platform_finddevs(pcap_if_t **alldevsp, char *err_str) 152190214Srpaulo{ 153190214Srpaulo struct dirent* data; 154190214Srpaulo int ret = 0; 155190214Srpaulo DIR* dir; 156214518Srpaulo int n; 157214518Srpaulo char* name; 158214518Srpaulo size_t len; 159190214Srpaulo 160214518Srpaulo /* try scanning sysfs usb bus directory */ 161214518Srpaulo dir = opendir(SYS_USB_BUS_DIR); 162214518Srpaulo if (dir != NULL) { 163214518Srpaulo while ((ret == 0) && ((data = readdir(dir)) != 0)) { 164214518Srpaulo name = data->d_name; 165190214Srpaulo 166214518Srpaulo if (strncmp(name, "usb", 3) != 0) 167214518Srpaulo continue; 168190214Srpaulo 169214518Srpaulo if (sscanf(&name[3], "%d", &n) == 0) 170214518Srpaulo continue; 171214518Srpaulo 172214518Srpaulo ret = usb_dev_add(alldevsp, n, err_str); 173214518Srpaulo } 174214518Srpaulo 175214518Srpaulo closedir(dir); 176214518Srpaulo return ret; 177190214Srpaulo } 178190214Srpaulo 179214518Srpaulo /* that didn't work; try scanning procfs usb bus directory */ 180214518Srpaulo dir = opendir(PROC_USB_BUS_DIR); 181214518Srpaulo if (dir != NULL) { 182214518Srpaulo while ((ret == 0) && ((data = readdir(dir)) != 0)) { 183214518Srpaulo name = data->d_name; 184214518Srpaulo len = strlen(name); 185214518Srpaulo 186214518Srpaulo /* if this file name does not end with a number it's not of our interest */ 187214518Srpaulo if ((len < 1) || !isdigit(name[--len])) 188214518Srpaulo continue; 189214518Srpaulo while (isdigit(name[--len])); 190214518Srpaulo if (sscanf(&name[len+1], "%d", &n) != 1) 191214518Srpaulo continue; 192214518Srpaulo 193214518Srpaulo ret = usb_dev_add(alldevsp, n, err_str); 194214518Srpaulo } 195214518Srpaulo 196214518Srpaulo closedir(dir); 197214518Srpaulo return ret; 198214518Srpaulo } 199214518Srpaulo 200214518Srpaulo /* neither of them worked */ 201214518Srpaulo return 0; 202190214Srpaulo} 203190214Srpaulo 204190214Srpaulostatic 205190214Srpauloint usb_mmap(pcap_t* handle) 206190214Srpaulo{ 207190214Srpaulo int len = ioctl(handle->fd, MON_IOCQ_RING_SIZE); 208190214Srpaulo if (len < 0) 209190214Srpaulo return 0; 210190214Srpaulo 211214518Srpaulo handle->md.mmapbuflen = len; 212214518Srpaulo handle->md.mmapbuf = mmap(0, handle->md.mmapbuflen, PROT_READ, 213214518Srpaulo MAP_SHARED, handle->fd, 0); 214214518Srpaulo return handle->md.mmapbuf != MAP_FAILED; 215190214Srpaulo} 216190214Srpaulo 217214518Srpaulo#define CTRL_TIMEOUT (5*1000) /* milliseconds */ 218214518Srpaulo 219214518Srpaulo#define USB_DIR_IN 0x80 220214518Srpaulo#define USB_TYPE_STANDARD 0x00 221214518Srpaulo#define USB_RECIP_DEVICE 0x00 222214518Srpaulo 223214518Srpaulo#define USB_REQ_GET_DESCRIPTOR 6 224214518Srpaulo 225214518Srpaulo#define USB_DT_DEVICE 1 226214518Srpaulo 227214518Srpaulo/* probe the descriptors of the devices attached to the bus */ 228214518Srpaulo/* the descriptors will end up in the captured packet stream */ 229214518Srpaulo/* and be decoded by external apps like wireshark */ 230214518Srpaulo/* without these identifying probes packet data can't be fully decoded */ 231214518Srpaulostatic void 232214518Srpauloprobe_devices(int bus) 233214518Srpaulo{ 234214518Srpaulo struct usbdevfs_ctrltransfer ctrl; 235214518Srpaulo struct dirent* data; 236214518Srpaulo int ret = 0; 237214518Srpaulo char buf[40]; 238214518Srpaulo DIR* dir; 239214518Srpaulo 240214518Srpaulo /* scan usb bus directories for device nodes */ 241214518Srpaulo snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d", bus); 242214518Srpaulo dir = opendir(buf); 243214518Srpaulo if (!dir) 244214518Srpaulo return; 245214518Srpaulo 246214518Srpaulo while ((ret >= 0) && ((data = readdir(dir)) != 0)) { 247214518Srpaulo int fd; 248214518Srpaulo char* name = data->d_name; 249214518Srpaulo 250214518Srpaulo if (name[0] == '.') 251214518Srpaulo continue; 252214518Srpaulo 253214518Srpaulo snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d/%s", bus, data->d_name); 254214518Srpaulo 255214518Srpaulo fd = open(buf, O_RDWR); 256214518Srpaulo if (fd == -1) 257214518Srpaulo continue; 258214518Srpaulo 259214518Srpaulo /* 260214518Srpaulo * Sigh. Different kernels have different member names 261214518Srpaulo * for this structure. 262214518Srpaulo */ 263214518Srpaulo#ifdef HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE 264214518Srpaulo ctrl.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; 265214518Srpaulo ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; 266214518Srpaulo ctrl.wValue = USB_DT_DEVICE << 8; 267214518Srpaulo ctrl.wIndex = 0; 268214518Srpaulo ctrl.wLength = sizeof(buf); 269214518Srpaulo#else 270214518Srpaulo ctrl.requesttype = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; 271214518Srpaulo ctrl.request = USB_REQ_GET_DESCRIPTOR; 272214518Srpaulo ctrl.value = USB_DT_DEVICE << 8; 273214518Srpaulo ctrl.index = 0; 274214518Srpaulo ctrl.length = sizeof(buf); 275214518Srpaulo#endif 276214518Srpaulo ctrl.data = buf; 277214518Srpaulo ctrl.timeout = CTRL_TIMEOUT; 278214518Srpaulo 279214518Srpaulo ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl); 280214518Srpaulo 281214518Srpaulo close(fd); 282214518Srpaulo } 283214518Srpaulo closedir(dir); 284214518Srpaulo} 285214518Srpaulo 286190214Srpaulopcap_t * 287190214Srpaulousb_create(const char *device, char *ebuf) 288190214Srpaulo{ 289190214Srpaulo pcap_t *p; 290190214Srpaulo 291190214Srpaulo p = pcap_create_common(device, ebuf); 292190214Srpaulo if (p == NULL) 293190214Srpaulo return (NULL); 294190214Srpaulo 295190214Srpaulo p->activate_op = usb_activate; 296190214Srpaulo return (p); 297190214Srpaulo} 298190214Srpaulo 299190214Srpaulostatic int 300190214Srpaulousb_activate(pcap_t* handle) 301190214Srpaulo{ 302190214Srpaulo char full_path[USB_LINE_LEN]; 303190214Srpaulo 304190214Srpaulo /* Initialize some components of the pcap structure. */ 305190214Srpaulo handle->bufsize = handle->snapshot; 306190214Srpaulo handle->offset = 0; 307190214Srpaulo handle->linktype = DLT_USB_LINUX; 308190214Srpaulo 309190214Srpaulo handle->inject_op = usb_inject_linux; 310235426Sdelphij handle->setfilter_op = install_bpf_program; /* no kernel filtering */ 311190214Srpaulo handle->setdirection_op = usb_setdirection_linux; 312190214Srpaulo handle->set_datalink_op = NULL; /* can't change data link type */ 313190214Srpaulo handle->getnonblock_op = pcap_getnonblock_fd; 314190214Srpaulo handle->setnonblock_op = pcap_setnonblock_fd; 315190214Srpaulo 316190214Srpaulo /*get usb bus index from device name */ 317190214Srpaulo if (sscanf(handle->opt.source, USB_IFACE"%d", &handle->md.ifindex) != 1) 318190214Srpaulo { 319190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 320190214Srpaulo "Can't get USB bus index from %s", handle->opt.source); 321190214Srpaulo return PCAP_ERROR; 322190214Srpaulo } 323190214Srpaulo 324190214Srpaulo /*now select the read method: try to open binary interface */ 325190214Srpaulo snprintf(full_path, USB_LINE_LEN, LINUX_USB_MON_DEV"%d", handle->md.ifindex); 326190214Srpaulo handle->fd = open(full_path, O_RDONLY, 0); 327190214Srpaulo if (handle->fd >= 0) 328190214Srpaulo { 329190214Srpaulo if (handle->opt.rfmon) { 330190214Srpaulo /* 331190214Srpaulo * Monitor mode doesn't apply to USB devices. 332190214Srpaulo */ 333214518Srpaulo close(handle->fd); 334190214Srpaulo return PCAP_ERROR_RFMON_NOTSUP; 335190214Srpaulo } 336190214Srpaulo 337190214Srpaulo /* binary api is available, try to use fast mmap access */ 338190214Srpaulo if (usb_mmap(handle)) { 339214518Srpaulo handle->linktype = DLT_USB_LINUX_MMAPPED; 340190214Srpaulo handle->stats_op = usb_stats_linux_bin; 341190214Srpaulo handle->read_op = usb_read_linux_mmap; 342190214Srpaulo handle->cleanup_op = usb_cleanup_linux_mmap; 343214518Srpaulo probe_devices(handle->md.ifindex); 344190214Srpaulo 345190214Srpaulo /* 346190214Srpaulo * "handle->fd" is a real file, so "select()" and 347190214Srpaulo * "poll()" work on it. 348190214Srpaulo */ 349190214Srpaulo handle->selectable_fd = handle->fd; 350190214Srpaulo return 0; 351190214Srpaulo } 352190214Srpaulo 353190214Srpaulo /* can't mmap, use plain binary interface access */ 354190214Srpaulo handle->stats_op = usb_stats_linux_bin; 355190214Srpaulo handle->read_op = usb_read_linux_bin; 356214518Srpaulo probe_devices(handle->md.ifindex); 357190214Srpaulo } 358190214Srpaulo else { 359190214Srpaulo /*Binary interface not available, try open text interface */ 360190214Srpaulo snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR"/%dt", handle->md.ifindex); 361190214Srpaulo handle->fd = open(full_path, O_RDONLY, 0); 362190214Srpaulo if (handle->fd < 0) 363190214Srpaulo { 364214518Srpaulo if (errno == ENOENT) 365214518Srpaulo { 366214518Srpaulo /* 367214518Srpaulo * Not found at the new location; try 368214518Srpaulo * the old location. 369214518Srpaulo */ 370214518Srpaulo snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%dt", handle->md.ifindex); 371214518Srpaulo handle->fd = open(full_path, O_RDONLY, 0); 372214518Srpaulo } 373214518Srpaulo if (handle->fd < 0) { 374214518Srpaulo /* no more fallback, give it up*/ 375214518Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 376214518Srpaulo "Can't open USB bus file %s: %s", full_path, strerror(errno)); 377214518Srpaulo return PCAP_ERROR; 378214518Srpaulo } 379190214Srpaulo } 380214518Srpaulo 381214518Srpaulo if (handle->opt.rfmon) { 382214518Srpaulo /* 383214518Srpaulo * Monitor mode doesn't apply to USB devices. 384214518Srpaulo */ 385214518Srpaulo close(handle->fd); 386214518Srpaulo return PCAP_ERROR_RFMON_NOTSUP; 387214518Srpaulo } 388214518Srpaulo 389190214Srpaulo handle->stats_op = usb_stats_linux; 390190214Srpaulo handle->read_op = usb_read_linux; 391190214Srpaulo } 392190214Srpaulo 393190214Srpaulo /* 394190214Srpaulo * "handle->fd" is a real file, so "select()" and "poll()" 395190214Srpaulo * work on it. 396190214Srpaulo */ 397190214Srpaulo handle->selectable_fd = handle->fd; 398190214Srpaulo 399190214Srpaulo /* for plain binary access and text access we need to allocate the read 400190214Srpaulo * buffer */ 401190214Srpaulo handle->buffer = malloc(handle->bufsize); 402190214Srpaulo if (!handle->buffer) { 403190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 404190214Srpaulo "malloc: %s", pcap_strerror(errno)); 405214518Srpaulo close(handle->fd); 406190214Srpaulo return PCAP_ERROR; 407190214Srpaulo } 408190214Srpaulo return 0; 409190214Srpaulo} 410190214Srpaulo 411190214Srpaulostatic inline int 412190214Srpauloascii_to_int(char c) 413190214Srpaulo{ 414190214Srpaulo return c < 'A' ? c- '0': ((c<'a') ? c - 'A' + 10: c-'a'+10); 415190214Srpaulo} 416190214Srpaulo 417190214Srpaulo/* 418190214Srpaulo * see <linux-kernel-source>/Documentation/usb/usbmon.txt and 419190214Srpaulo * <linux-kernel-source>/drivers/usb/mon/mon_text.c for urb string 420190214Srpaulo * format description 421190214Srpaulo */ 422190214Srpaulostatic int 423190214Srpaulousb_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 424190214Srpaulo{ 425190214Srpaulo /* see: 426190214Srpaulo * /usr/src/linux/Documentation/usb/usbmon.txt 427190214Srpaulo * for message format 428190214Srpaulo */ 429190214Srpaulo unsigned timestamp; 430190214Srpaulo int tag, cnt, ep_num, dev_addr, dummy, ret, urb_len, data_len; 431190214Srpaulo char etype, pipeid1, pipeid2, status[16], urb_tag, line[USB_LINE_LEN]; 432190214Srpaulo char *string = line; 433190214Srpaulo u_char * rawdata = handle->buffer; 434190214Srpaulo struct pcap_pkthdr pkth; 435190214Srpaulo pcap_usb_header* uhdr = (pcap_usb_header*)handle->buffer; 436190214Srpaulo u_char urb_transfer=0; 437190214Srpaulo int incoming=0; 438190214Srpaulo 439190214Srpaulo /* ignore interrupt system call errors */ 440190214Srpaulo do { 441190214Srpaulo ret = read(handle->fd, line, USB_LINE_LEN - 1); 442190214Srpaulo if (handle->break_loop) 443190214Srpaulo { 444190214Srpaulo handle->break_loop = 0; 445190214Srpaulo return -2; 446190214Srpaulo } 447190214Srpaulo } while ((ret == -1) && (errno == EINTR)); 448190214Srpaulo if (ret < 0) 449190214Srpaulo { 450190214Srpaulo if (errno == EAGAIN) 451190214Srpaulo return 0; /* no data there */ 452190214Srpaulo 453190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 454190214Srpaulo "Can't read from fd %d: %s", handle->fd, strerror(errno)); 455190214Srpaulo return -1; 456190214Srpaulo } 457190214Srpaulo 458190214Srpaulo /* read urb header; %n argument may increment return value, but it's 459190214Srpaulo * not mandatory, so does not count on it*/ 460190214Srpaulo string[ret] = 0; 461190214Srpaulo ret = sscanf(string, "%x %d %c %c%c:%d:%d %s%n", &tag, ×tamp, &etype, 462190214Srpaulo &pipeid1, &pipeid2, &dev_addr, &ep_num, status, 463190214Srpaulo &cnt); 464190214Srpaulo if (ret < 8) 465190214Srpaulo { 466190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 467190214Srpaulo "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)", 468190214Srpaulo string, ret); 469190214Srpaulo return -1; 470190214Srpaulo } 471190214Srpaulo uhdr->id = tag; 472190214Srpaulo uhdr->device_address = dev_addr; 473190214Srpaulo uhdr->bus_id = handle->md.ifindex; 474190214Srpaulo uhdr->status = 0; 475190214Srpaulo string += cnt; 476190214Srpaulo 477190214Srpaulo /* don't use usbmon provided timestamp, since it have low precision*/ 478190214Srpaulo if (gettimeofday(&pkth.ts, NULL) < 0) 479190214Srpaulo { 480190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 481190214Srpaulo "Can't get timestamp for message '%s' %d:%s", 482190214Srpaulo string, errno, strerror(errno)); 483190214Srpaulo return -1; 484190214Srpaulo } 485190214Srpaulo uhdr->ts_sec = pkth.ts.tv_sec; 486190214Srpaulo uhdr->ts_usec = pkth.ts.tv_usec; 487190214Srpaulo 488190214Srpaulo /* parse endpoint information */ 489190214Srpaulo if (pipeid1 == 'C') 490190214Srpaulo urb_transfer = URB_CONTROL; 491190214Srpaulo else if (pipeid1 == 'Z') 492190214Srpaulo urb_transfer = URB_ISOCHRONOUS; 493190214Srpaulo else if (pipeid1 == 'I') 494190214Srpaulo urb_transfer = URB_INTERRUPT; 495190214Srpaulo else if (pipeid1 == 'B') 496190214Srpaulo urb_transfer = URB_BULK; 497190214Srpaulo if (pipeid2 == 'i') { 498214518Srpaulo ep_num |= URB_TRANSFER_IN; 499190214Srpaulo incoming = 1; 500190214Srpaulo } 501190214Srpaulo if (etype == 'C') 502190214Srpaulo incoming = !incoming; 503190214Srpaulo 504190214Srpaulo /* direction check*/ 505190214Srpaulo if (incoming) 506190214Srpaulo { 507190214Srpaulo if (handle->direction == PCAP_D_OUT) 508190214Srpaulo return 0; 509190214Srpaulo } 510190214Srpaulo else 511190214Srpaulo if (handle->direction == PCAP_D_IN) 512190214Srpaulo return 0; 513190214Srpaulo uhdr->event_type = etype; 514190214Srpaulo uhdr->transfer_type = urb_transfer; 515214518Srpaulo uhdr->endpoint_number = ep_num; 516190214Srpaulo pkth.caplen = sizeof(pcap_usb_header); 517190214Srpaulo rawdata += sizeof(pcap_usb_header); 518190214Srpaulo 519190214Srpaulo /* check if this is a setup packet */ 520190214Srpaulo ret = sscanf(status, "%d", &dummy); 521190214Srpaulo if (ret != 1) 522190214Srpaulo { 523190214Srpaulo /* this a setup packet, setup data can be filled with underscore if 524190214Srpaulo * usbmon has not been able to read them, so we must parse this fields as 525190214Srpaulo * strings */ 526190214Srpaulo pcap_usb_setup* shdr; 527190214Srpaulo char str1[3], str2[3], str3[5], str4[5], str5[5]; 528190214Srpaulo ret = sscanf(string, "%s %s %s %s %s%n", str1, str2, str3, str4, 529190214Srpaulo str5, &cnt); 530190214Srpaulo if (ret < 5) 531190214Srpaulo { 532190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 533190214Srpaulo "Can't parse USB bus message '%s', too few tokens (expected 5 got %d)", 534190214Srpaulo string, ret); 535190214Srpaulo return -1; 536190214Srpaulo } 537190214Srpaulo string += cnt; 538190214Srpaulo 539190214Srpaulo /* try to convert to corresponding integer */ 540190214Srpaulo shdr = &uhdr->setup; 541190214Srpaulo shdr->bmRequestType = strtoul(str1, 0, 16); 542190214Srpaulo shdr->bRequest = strtoul(str2, 0, 16); 543190214Srpaulo shdr->wValue = htols(strtoul(str3, 0, 16)); 544190214Srpaulo shdr->wIndex = htols(strtoul(str4, 0, 16)); 545190214Srpaulo shdr->wLength = htols(strtoul(str5, 0, 16)); 546190214Srpaulo 547190214Srpaulo uhdr->setup_flag = 0; 548190214Srpaulo } 549190214Srpaulo else 550190214Srpaulo uhdr->setup_flag = 1; 551190214Srpaulo 552190214Srpaulo /* read urb data */ 553190214Srpaulo ret = sscanf(string, " %d%n", &urb_len, &cnt); 554190214Srpaulo if (ret < 1) 555190214Srpaulo { 556190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 557190214Srpaulo "Can't parse urb length from '%s'", string); 558190214Srpaulo return -1; 559190214Srpaulo } 560190214Srpaulo string += cnt; 561190214Srpaulo 562190214Srpaulo /* urb tag is not present if urb length is 0, so we can stop here 563190214Srpaulo * text parsing */ 564190214Srpaulo pkth.len = urb_len+pkth.caplen; 565190214Srpaulo uhdr->urb_len = urb_len; 566190214Srpaulo uhdr->data_flag = 1; 567190214Srpaulo data_len = 0; 568214518Srpaulo if (uhdr->urb_len == 0) 569190214Srpaulo goto got; 570190214Srpaulo 571190214Srpaulo /* check for data presence; data is present if and only if urb tag is '=' */ 572190214Srpaulo if (sscanf(string, " %c", &urb_tag) != 1) 573190214Srpaulo { 574190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 575190214Srpaulo "Can't parse urb tag from '%s'", string); 576190214Srpaulo return -1; 577190214Srpaulo } 578190214Srpaulo 579190214Srpaulo if (urb_tag != '=') 580190214Srpaulo goto got; 581190214Srpaulo 582190214Srpaulo /* skip urb tag and following space */ 583190214Srpaulo string += 3; 584190214Srpaulo 585190214Srpaulo /* if we reach this point we got some urb data*/ 586190214Srpaulo uhdr->data_flag = 0; 587190214Srpaulo 588190214Srpaulo /* read all urb data; if urb length is greater then the usbmon internal 589190214Srpaulo * buffer length used by the kernel to spool the URB, we get only 590190214Srpaulo * a partial information. 591190214Srpaulo * At least until linux 2.6.17 there is no way to set usbmon intenal buffer 592190214Srpaulo * length and default value is 130. */ 593190214Srpaulo while ((string[0] != 0) && (string[1] != 0) && (pkth.caplen < handle->snapshot)) 594190214Srpaulo { 595190214Srpaulo rawdata[0] = ascii_to_int(string[0]) * 16 + ascii_to_int(string[1]); 596190214Srpaulo rawdata++; 597190214Srpaulo string+=2; 598190214Srpaulo if (string[0] == ' ') 599190214Srpaulo string++; 600190214Srpaulo pkth.caplen++; 601190214Srpaulo data_len++; 602190214Srpaulo } 603190214Srpaulo 604190214Srpaulogot: 605190214Srpaulo uhdr->data_len = data_len; 606190214Srpaulo if (pkth.caplen > handle->snapshot) 607190214Srpaulo pkth.caplen = handle->snapshot; 608190214Srpaulo 609235426Sdelphij if (handle->fcode.bf_insns == NULL || 610235426Sdelphij bpf_filter(handle->fcode.bf_insns, handle->buffer, 611235426Sdelphij pkth.len, pkth.caplen)) { 612235426Sdelphij handle->md.packets_read++; 613235426Sdelphij callback(user, &pkth, handle->buffer); 614235426Sdelphij return 1; 615235426Sdelphij } 616235426Sdelphij return 0; /* didn't pass filter */ 617190214Srpaulo} 618190214Srpaulo 619190214Srpaulostatic int 620190214Srpaulousb_inject_linux(pcap_t *handle, const void *buf, size_t size) 621190214Srpaulo{ 622190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " 623190214Srpaulo "USB devices"); 624190214Srpaulo return (-1); 625190214Srpaulo} 626190214Srpaulo 627190214Srpaulostatic int 628190214Srpaulousb_stats_linux(pcap_t *handle, struct pcap_stat *stats) 629190214Srpaulo{ 630190214Srpaulo int dummy, ret, consumed, cnt; 631190214Srpaulo char string[USB_LINE_LEN]; 632190214Srpaulo char token[USB_LINE_LEN]; 633190214Srpaulo char * ptr = string; 634214518Srpaulo int fd; 635214518Srpaulo 636190214Srpaulo snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handle->md.ifindex); 637214518Srpaulo fd = open(string, O_RDONLY, 0); 638190214Srpaulo if (fd < 0) 639190214Srpaulo { 640214518Srpaulo if (errno == ENOENT) 641214518Srpaulo { 642214518Srpaulo /* 643214518Srpaulo * Not found at the new location; try the old 644214518Srpaulo * location. 645214518Srpaulo */ 646214518Srpaulo snprintf(string, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%ds", handle->md.ifindex); 647214518Srpaulo fd = open(string, O_RDONLY, 0); 648214518Srpaulo } 649214518Srpaulo if (fd < 0) { 650214518Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 651214518Srpaulo "Can't open USB stats file %s: %s", 652214518Srpaulo string, strerror(errno)); 653214518Srpaulo return -1; 654214518Srpaulo } 655190214Srpaulo } 656190214Srpaulo 657190214Srpaulo /* read stats line */ 658190214Srpaulo do { 659190214Srpaulo ret = read(fd, string, USB_LINE_LEN-1); 660190214Srpaulo } while ((ret == -1) && (errno == EINTR)); 661190214Srpaulo close(fd); 662190214Srpaulo 663190214Srpaulo if (ret < 0) 664190214Srpaulo { 665190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 666190214Srpaulo "Can't read stats from fd %d ", fd); 667190214Srpaulo return -1; 668190214Srpaulo } 669190214Srpaulo string[ret] = 0; 670190214Srpaulo 671190214Srpaulo /* extract info on dropped urbs */ 672190214Srpaulo for (consumed=0; consumed < ret; ) { 673190214Srpaulo /* from the sscanf man page: 674190214Srpaulo * The C standard says: "Execution of a %n directive does 675190214Srpaulo * not increment the assignment count returned at the completion 676190214Srpaulo * of execution" but the Corrigendum seems to contradict this. 677190214Srpaulo * Do not make any assumptions on the effect of %n conversions 678190214Srpaulo * on the return value and explicitly check for cnt assignmet*/ 679214518Srpaulo int ntok; 680214518Srpaulo 681190214Srpaulo cnt = -1; 682214518Srpaulo ntok = sscanf(ptr, "%s%n", token, &cnt); 683190214Srpaulo if ((ntok < 1) || (cnt < 0)) 684190214Srpaulo break; 685190214Srpaulo consumed += cnt; 686190214Srpaulo ptr += cnt; 687190214Srpaulo if (strcmp(token, "nreaders") == 0) 688190214Srpaulo ret = sscanf(ptr, "%d", &stats->ps_drop); 689190214Srpaulo else 690190214Srpaulo ret = sscanf(ptr, "%d", &dummy); 691190214Srpaulo if (ntok != 1) 692190214Srpaulo break; 693190214Srpaulo consumed += cnt; 694190214Srpaulo ptr += cnt; 695190214Srpaulo } 696190214Srpaulo 697190214Srpaulo stats->ps_recv = handle->md.packets_read; 698190214Srpaulo stats->ps_ifdrop = 0; 699190214Srpaulo return 0; 700190214Srpaulo} 701190214Srpaulo 702190214Srpaulostatic int 703190214Srpaulousb_setdirection_linux(pcap_t *p, pcap_direction_t d) 704190214Srpaulo{ 705190214Srpaulo p->direction = d; 706190214Srpaulo return 0; 707190214Srpaulo} 708190214Srpaulo 709190214Srpaulo 710190214Srpaulostatic int 711190214Srpaulousb_stats_linux_bin(pcap_t *handle, struct pcap_stat *stats) 712190214Srpaulo{ 713190214Srpaulo int ret; 714190214Srpaulo struct mon_bin_stats st; 715190214Srpaulo ret = ioctl(handle->fd, MON_IOCG_STATS, &st); 716190214Srpaulo if (ret < 0) 717190214Srpaulo { 718190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 719190214Srpaulo "Can't read stats from fd %d:%s ", handle->fd, strerror(errno)); 720190214Srpaulo return -1; 721190214Srpaulo } 722190214Srpaulo 723190214Srpaulo stats->ps_recv = handle->md.packets_read + st.queued; 724214518Srpaulo stats->ps_drop = st.dropped; 725214518Srpaulo stats->ps_ifdrop = 0; 726190214Srpaulo return 0; 727190214Srpaulo} 728190214Srpaulo 729190214Srpaulo/* 730190214Srpaulo * see <linux-kernel-source>/Documentation/usb/usbmon.txt and 731190214Srpaulo * <linux-kernel-source>/drivers/usb/mon/mon_bin.c binary ABI 732190214Srpaulo */ 733190214Srpaulostatic int 734190214Srpaulousb_read_linux_bin(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 735190214Srpaulo{ 736190214Srpaulo struct mon_bin_get info; 737190214Srpaulo int ret; 738190214Srpaulo struct pcap_pkthdr pkth; 739190214Srpaulo int clen = handle->snapshot - sizeof(pcap_usb_header); 740190214Srpaulo 741190214Srpaulo /* the usb header is going to be part of 'packet' data*/ 742190214Srpaulo info.hdr = (pcap_usb_header*) handle->buffer; 743190214Srpaulo info.data = handle->buffer + sizeof(pcap_usb_header); 744190214Srpaulo info.data_len = clen; 745190214Srpaulo 746190214Srpaulo /* ignore interrupt system call errors */ 747190214Srpaulo do { 748190214Srpaulo ret = ioctl(handle->fd, MON_IOCX_GET, &info); 749190214Srpaulo if (handle->break_loop) 750190214Srpaulo { 751190214Srpaulo handle->break_loop = 0; 752190214Srpaulo return -2; 753190214Srpaulo } 754190214Srpaulo } while ((ret == -1) && (errno == EINTR)); 755190214Srpaulo if (ret < 0) 756190214Srpaulo { 757190214Srpaulo if (errno == EAGAIN) 758190214Srpaulo return 0; /* no data there */ 759190214Srpaulo 760190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 761190214Srpaulo "Can't read from fd %d: %s", handle->fd, strerror(errno)); 762190214Srpaulo return -1; 763190214Srpaulo } 764190214Srpaulo 765190214Srpaulo /* we can get less that than really captured from kernel, depending on 766190214Srpaulo * snaplen, so adjust header accordingly */ 767190214Srpaulo if (info.hdr->data_len < clen) 768190214Srpaulo clen = info.hdr->data_len; 769190214Srpaulo info.hdr->data_len = clen; 770190214Srpaulo pkth.caplen = clen + sizeof(pcap_usb_header); 771214518Srpaulo pkth.len = info.hdr->data_len + sizeof(pcap_usb_header); 772190214Srpaulo pkth.ts.tv_sec = info.hdr->ts_sec; 773190214Srpaulo pkth.ts.tv_usec = info.hdr->ts_usec; 774190214Srpaulo 775235426Sdelphij if (handle->fcode.bf_insns == NULL || 776235426Sdelphij bpf_filter(handle->fcode.bf_insns, handle->buffer, 777235426Sdelphij pkth.len, pkth.caplen)) { 778235426Sdelphij handle->md.packets_read++; 779235426Sdelphij callback(user, &pkth, handle->buffer); 780235426Sdelphij return 1; 781235426Sdelphij } 782235426Sdelphij 783235426Sdelphij return 0; /* didn't pass filter */ 784190214Srpaulo} 785190214Srpaulo 786190214Srpaulo/* 787190214Srpaulo * see <linux-kernel-source>/Documentation/usb/usbmon.txt and 788190214Srpaulo * <linux-kernel-source>/drivers/usb/mon/mon_bin.c binary ABI 789190214Srpaulo */ 790190214Srpaulo#define VEC_SIZE 32 791190214Srpaulostatic int 792190214Srpaulousb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 793190214Srpaulo{ 794190214Srpaulo struct mon_bin_mfetch fetch; 795190214Srpaulo int32_t vec[VEC_SIZE]; 796190214Srpaulo struct pcap_pkthdr pkth; 797190214Srpaulo pcap_usb_header* hdr; 798190214Srpaulo int nflush = 0; 799190214Srpaulo int packets = 0; 800214518Srpaulo int clen, max_clen; 801190214Srpaulo 802214518Srpaulo max_clen = handle->snapshot - sizeof(pcap_usb_header); 803214518Srpaulo 804190214Srpaulo for (;;) { 805190214Srpaulo int i, ret; 806190214Srpaulo int limit = max_packets - packets; 807190214Srpaulo if (limit <= 0) 808190214Srpaulo limit = VEC_SIZE; 809190214Srpaulo if (limit > VEC_SIZE) 810190214Srpaulo limit = VEC_SIZE; 811190214Srpaulo 812190214Srpaulo /* try to fetch as many events as possible*/ 813190214Srpaulo fetch.offvec = vec; 814190214Srpaulo fetch.nfetch = limit; 815190214Srpaulo fetch.nflush = nflush; 816190214Srpaulo /* ignore interrupt system call errors */ 817190214Srpaulo do { 818190214Srpaulo ret = ioctl(handle->fd, MON_IOCX_MFETCH, &fetch); 819190214Srpaulo if (handle->break_loop) 820190214Srpaulo { 821190214Srpaulo handle->break_loop = 0; 822190214Srpaulo return -2; 823190214Srpaulo } 824190214Srpaulo } while ((ret == -1) && (errno == EINTR)); 825190214Srpaulo if (ret < 0) 826190214Srpaulo { 827190214Srpaulo if (errno == EAGAIN) 828190214Srpaulo return 0; /* no data there */ 829190214Srpaulo 830190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 831190214Srpaulo "Can't mfetch fd %d: %s", handle->fd, strerror(errno)); 832190214Srpaulo return -1; 833190214Srpaulo } 834190214Srpaulo 835190214Srpaulo /* keep track of processed events, we will flush them later */ 836190214Srpaulo nflush = fetch.nfetch; 837190214Srpaulo for (i=0; i<fetch.nfetch; ++i) { 838190214Srpaulo /* discard filler */ 839214518Srpaulo hdr = (pcap_usb_header*) &handle->md.mmapbuf[vec[i]]; 840190214Srpaulo if (hdr->event_type == '@') 841190214Srpaulo continue; 842190214Srpaulo 843214518Srpaulo /* we can get less that than really captured from kernel, depending on 844214518Srpaulo * snaplen, so adjust header accordingly */ 845214518Srpaulo clen = max_clen; 846214518Srpaulo if (hdr->data_len < clen) 847214518Srpaulo clen = hdr->data_len; 848214518Srpaulo 849190214Srpaulo /* get packet info from header*/ 850214518Srpaulo pkth.caplen = clen + sizeof(pcap_usb_header_mmapped); 851214518Srpaulo pkth.len = hdr->data_len + sizeof(pcap_usb_header_mmapped); 852190214Srpaulo pkth.ts.tv_sec = hdr->ts_sec; 853190214Srpaulo pkth.ts.tv_usec = hdr->ts_usec; 854190214Srpaulo 855235426Sdelphij if (handle->fcode.bf_insns == NULL || 856235426Sdelphij bpf_filter(handle->fcode.bf_insns, (u_char*) hdr, 857235426Sdelphij pkth.len, pkth.caplen)) { 858235426Sdelphij handle->md.packets_read++; 859235426Sdelphij callback(user, &pkth, (u_char*) hdr); 860235426Sdelphij packets++; 861235426Sdelphij } 862190214Srpaulo } 863190214Srpaulo 864190214Srpaulo /* with max_packets <= 0 we stop afer the first chunk*/ 865190214Srpaulo if ((max_packets <= 0) || (packets == max_packets)) 866190214Srpaulo break; 867190214Srpaulo } 868190214Srpaulo 869190214Srpaulo /* flush pending events*/ 870190214Srpaulo ioctl(handle->fd, MON_IOCH_MFLUSH, nflush); 871190214Srpaulo return packets; 872190214Srpaulo} 873190214Srpaulo 874190214Srpaulostatic void 875190214Srpaulousb_cleanup_linux_mmap(pcap_t* handle) 876190214Srpaulo{ 877214518Srpaulo /* if we have a memory-mapped buffer, unmap it */ 878214518Srpaulo if (handle->md.mmapbuf != NULL) { 879214518Srpaulo munmap(handle->md.mmapbuf, handle->md.mmapbuflen); 880214518Srpaulo handle->md.mmapbuf = NULL; 881214518Srpaulo } 882190214Srpaulo pcap_cleanup_live_common(handle); 883190214Srpaulo} 884