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 151251129Sdelphijusb_findalldevs(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 * 287251129Sdelphijusb_create(const char *device, char *ebuf, int *is_ours) 288190214Srpaulo{ 289251129Sdelphij const char *cp; 290251129Sdelphij char *cpend; 291251129Sdelphij long devnum; 292190214Srpaulo pcap_t *p; 293190214Srpaulo 294251129Sdelphij /* Does this look like a USB monitoring device? */ 295251129Sdelphij cp = strrchr(device, '/'); 296251129Sdelphij if (cp == NULL) 297251129Sdelphij cp = device; 298251129Sdelphij /* Does it begin with USB_IFACE? */ 299251129Sdelphij if (strncmp(cp, USB_IFACE, sizeof USB_IFACE - 1) != 0) { 300251129Sdelphij /* Nope, doesn't begin with USB_IFACE */ 301251129Sdelphij *is_ours = 0; 302251129Sdelphij return NULL; 303251129Sdelphij } 304251129Sdelphij /* Yes - is USB_IFACE followed by a number? */ 305251129Sdelphij cp += sizeof USB_IFACE - 1; 306251129Sdelphij devnum = strtol(cp, &cpend, 10); 307251129Sdelphij if (cpend == cp || *cpend != '\0') { 308251129Sdelphij /* Not followed by a number. */ 309251129Sdelphij *is_ours = 0; 310251129Sdelphij return NULL; 311251129Sdelphij } 312251129Sdelphij if (devnum < 0) { 313251129Sdelphij /* Followed by a non-valid number. */ 314251129Sdelphij *is_ours = 0; 315251129Sdelphij return NULL; 316251129Sdelphij } 317251129Sdelphij 318251129Sdelphij /* OK, it's probably ours. */ 319251129Sdelphij *is_ours = 1; 320251129Sdelphij 321190214Srpaulo p = pcap_create_common(device, ebuf); 322190214Srpaulo if (p == NULL) 323190214Srpaulo return (NULL); 324190214Srpaulo 325190214Srpaulo p->activate_op = usb_activate; 326190214Srpaulo return (p); 327190214Srpaulo} 328190214Srpaulo 329190214Srpaulostatic int 330190214Srpaulousb_activate(pcap_t* handle) 331190214Srpaulo{ 332190214Srpaulo char full_path[USB_LINE_LEN]; 333190214Srpaulo 334190214Srpaulo /* Initialize some components of the pcap structure. */ 335190214Srpaulo handle->bufsize = handle->snapshot; 336190214Srpaulo handle->offset = 0; 337190214Srpaulo handle->linktype = DLT_USB_LINUX; 338190214Srpaulo 339190214Srpaulo handle->inject_op = usb_inject_linux; 340235426Sdelphij handle->setfilter_op = install_bpf_program; /* no kernel filtering */ 341190214Srpaulo handle->setdirection_op = usb_setdirection_linux; 342190214Srpaulo handle->set_datalink_op = NULL; /* can't change data link type */ 343190214Srpaulo handle->getnonblock_op = pcap_getnonblock_fd; 344190214Srpaulo handle->setnonblock_op = pcap_setnonblock_fd; 345190214Srpaulo 346190214Srpaulo /*get usb bus index from device name */ 347190214Srpaulo if (sscanf(handle->opt.source, USB_IFACE"%d", &handle->md.ifindex) != 1) 348190214Srpaulo { 349190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 350190214Srpaulo "Can't get USB bus index from %s", handle->opt.source); 351190214Srpaulo return PCAP_ERROR; 352190214Srpaulo } 353190214Srpaulo 354190214Srpaulo /*now select the read method: try to open binary interface */ 355190214Srpaulo snprintf(full_path, USB_LINE_LEN, LINUX_USB_MON_DEV"%d", handle->md.ifindex); 356190214Srpaulo handle->fd = open(full_path, O_RDONLY, 0); 357190214Srpaulo if (handle->fd >= 0) 358190214Srpaulo { 359190214Srpaulo if (handle->opt.rfmon) { 360190214Srpaulo /* 361190214Srpaulo * Monitor mode doesn't apply to USB devices. 362190214Srpaulo */ 363214518Srpaulo close(handle->fd); 364190214Srpaulo return PCAP_ERROR_RFMON_NOTSUP; 365190214Srpaulo } 366190214Srpaulo 367190214Srpaulo /* binary api is available, try to use fast mmap access */ 368190214Srpaulo if (usb_mmap(handle)) { 369214518Srpaulo handle->linktype = DLT_USB_LINUX_MMAPPED; 370190214Srpaulo handle->stats_op = usb_stats_linux_bin; 371190214Srpaulo handle->read_op = usb_read_linux_mmap; 372190214Srpaulo handle->cleanup_op = usb_cleanup_linux_mmap; 373214518Srpaulo probe_devices(handle->md.ifindex); 374190214Srpaulo 375190214Srpaulo /* 376190214Srpaulo * "handle->fd" is a real file, so "select()" and 377190214Srpaulo * "poll()" work on it. 378190214Srpaulo */ 379190214Srpaulo handle->selectable_fd = handle->fd; 380190214Srpaulo return 0; 381190214Srpaulo } 382190214Srpaulo 383190214Srpaulo /* can't mmap, use plain binary interface access */ 384190214Srpaulo handle->stats_op = usb_stats_linux_bin; 385190214Srpaulo handle->read_op = usb_read_linux_bin; 386214518Srpaulo probe_devices(handle->md.ifindex); 387190214Srpaulo } 388190214Srpaulo else { 389190214Srpaulo /*Binary interface not available, try open text interface */ 390190214Srpaulo snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR"/%dt", handle->md.ifindex); 391190214Srpaulo handle->fd = open(full_path, O_RDONLY, 0); 392190214Srpaulo if (handle->fd < 0) 393190214Srpaulo { 394214518Srpaulo if (errno == ENOENT) 395214518Srpaulo { 396214518Srpaulo /* 397214518Srpaulo * Not found at the new location; try 398214518Srpaulo * the old location. 399214518Srpaulo */ 400214518Srpaulo snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%dt", handle->md.ifindex); 401214518Srpaulo handle->fd = open(full_path, O_RDONLY, 0); 402214518Srpaulo } 403214518Srpaulo if (handle->fd < 0) { 404214518Srpaulo /* no more fallback, give it up*/ 405214518Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 406214518Srpaulo "Can't open USB bus file %s: %s", full_path, strerror(errno)); 407214518Srpaulo return PCAP_ERROR; 408214518Srpaulo } 409190214Srpaulo } 410214518Srpaulo 411214518Srpaulo if (handle->opt.rfmon) { 412214518Srpaulo /* 413214518Srpaulo * Monitor mode doesn't apply to USB devices. 414214518Srpaulo */ 415214518Srpaulo close(handle->fd); 416214518Srpaulo return PCAP_ERROR_RFMON_NOTSUP; 417214518Srpaulo } 418214518Srpaulo 419190214Srpaulo handle->stats_op = usb_stats_linux; 420190214Srpaulo handle->read_op = usb_read_linux; 421190214Srpaulo } 422190214Srpaulo 423190214Srpaulo /* 424190214Srpaulo * "handle->fd" is a real file, so "select()" and "poll()" 425190214Srpaulo * work on it. 426190214Srpaulo */ 427190214Srpaulo handle->selectable_fd = handle->fd; 428190214Srpaulo 429190214Srpaulo /* for plain binary access and text access we need to allocate the read 430190214Srpaulo * buffer */ 431190214Srpaulo handle->buffer = malloc(handle->bufsize); 432190214Srpaulo if (!handle->buffer) { 433190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 434190214Srpaulo "malloc: %s", pcap_strerror(errno)); 435214518Srpaulo close(handle->fd); 436190214Srpaulo return PCAP_ERROR; 437190214Srpaulo } 438190214Srpaulo return 0; 439190214Srpaulo} 440190214Srpaulo 441190214Srpaulostatic inline int 442190214Srpauloascii_to_int(char c) 443190214Srpaulo{ 444190214Srpaulo return c < 'A' ? c- '0': ((c<'a') ? c - 'A' + 10: c-'a'+10); 445190214Srpaulo} 446190214Srpaulo 447190214Srpaulo/* 448190214Srpaulo * see <linux-kernel-source>/Documentation/usb/usbmon.txt and 449190214Srpaulo * <linux-kernel-source>/drivers/usb/mon/mon_text.c for urb string 450190214Srpaulo * format description 451190214Srpaulo */ 452190214Srpaulostatic int 453190214Srpaulousb_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 454190214Srpaulo{ 455190214Srpaulo /* see: 456190214Srpaulo * /usr/src/linux/Documentation/usb/usbmon.txt 457190214Srpaulo * for message format 458190214Srpaulo */ 459190214Srpaulo unsigned timestamp; 460190214Srpaulo int tag, cnt, ep_num, dev_addr, dummy, ret, urb_len, data_len; 461190214Srpaulo char etype, pipeid1, pipeid2, status[16], urb_tag, line[USB_LINE_LEN]; 462190214Srpaulo char *string = line; 463190214Srpaulo u_char * rawdata = handle->buffer; 464190214Srpaulo struct pcap_pkthdr pkth; 465190214Srpaulo pcap_usb_header* uhdr = (pcap_usb_header*)handle->buffer; 466190214Srpaulo u_char urb_transfer=0; 467190214Srpaulo int incoming=0; 468190214Srpaulo 469190214Srpaulo /* ignore interrupt system call errors */ 470190214Srpaulo do { 471190214Srpaulo ret = read(handle->fd, line, USB_LINE_LEN - 1); 472190214Srpaulo if (handle->break_loop) 473190214Srpaulo { 474190214Srpaulo handle->break_loop = 0; 475190214Srpaulo return -2; 476190214Srpaulo } 477190214Srpaulo } while ((ret == -1) && (errno == EINTR)); 478190214Srpaulo if (ret < 0) 479190214Srpaulo { 480190214Srpaulo if (errno == EAGAIN) 481190214Srpaulo return 0; /* no data there */ 482190214Srpaulo 483190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 484190214Srpaulo "Can't read from fd %d: %s", handle->fd, strerror(errno)); 485190214Srpaulo return -1; 486190214Srpaulo } 487190214Srpaulo 488190214Srpaulo /* read urb header; %n argument may increment return value, but it's 489190214Srpaulo * not mandatory, so does not count on it*/ 490190214Srpaulo string[ret] = 0; 491190214Srpaulo ret = sscanf(string, "%x %d %c %c%c:%d:%d %s%n", &tag, ×tamp, &etype, 492190214Srpaulo &pipeid1, &pipeid2, &dev_addr, &ep_num, status, 493190214Srpaulo &cnt); 494190214Srpaulo if (ret < 8) 495190214Srpaulo { 496190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 497190214Srpaulo "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)", 498190214Srpaulo string, ret); 499190214Srpaulo return -1; 500190214Srpaulo } 501190214Srpaulo uhdr->id = tag; 502190214Srpaulo uhdr->device_address = dev_addr; 503190214Srpaulo uhdr->bus_id = handle->md.ifindex; 504190214Srpaulo uhdr->status = 0; 505190214Srpaulo string += cnt; 506190214Srpaulo 507190214Srpaulo /* don't use usbmon provided timestamp, since it have low precision*/ 508190214Srpaulo if (gettimeofday(&pkth.ts, NULL) < 0) 509190214Srpaulo { 510190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 511190214Srpaulo "Can't get timestamp for message '%s' %d:%s", 512190214Srpaulo string, errno, strerror(errno)); 513190214Srpaulo return -1; 514190214Srpaulo } 515190214Srpaulo uhdr->ts_sec = pkth.ts.tv_sec; 516190214Srpaulo uhdr->ts_usec = pkth.ts.tv_usec; 517190214Srpaulo 518190214Srpaulo /* parse endpoint information */ 519190214Srpaulo if (pipeid1 == 'C') 520190214Srpaulo urb_transfer = URB_CONTROL; 521190214Srpaulo else if (pipeid1 == 'Z') 522190214Srpaulo urb_transfer = URB_ISOCHRONOUS; 523190214Srpaulo else if (pipeid1 == 'I') 524190214Srpaulo urb_transfer = URB_INTERRUPT; 525190214Srpaulo else if (pipeid1 == 'B') 526190214Srpaulo urb_transfer = URB_BULK; 527190214Srpaulo if (pipeid2 == 'i') { 528214518Srpaulo ep_num |= URB_TRANSFER_IN; 529190214Srpaulo incoming = 1; 530190214Srpaulo } 531190214Srpaulo if (etype == 'C') 532190214Srpaulo incoming = !incoming; 533190214Srpaulo 534190214Srpaulo /* direction check*/ 535190214Srpaulo if (incoming) 536190214Srpaulo { 537190214Srpaulo if (handle->direction == PCAP_D_OUT) 538190214Srpaulo return 0; 539190214Srpaulo } 540190214Srpaulo else 541190214Srpaulo if (handle->direction == PCAP_D_IN) 542190214Srpaulo return 0; 543190214Srpaulo uhdr->event_type = etype; 544190214Srpaulo uhdr->transfer_type = urb_transfer; 545214518Srpaulo uhdr->endpoint_number = ep_num; 546190214Srpaulo pkth.caplen = sizeof(pcap_usb_header); 547190214Srpaulo rawdata += sizeof(pcap_usb_header); 548190214Srpaulo 549190214Srpaulo /* check if this is a setup packet */ 550190214Srpaulo ret = sscanf(status, "%d", &dummy); 551190214Srpaulo if (ret != 1) 552190214Srpaulo { 553190214Srpaulo /* this a setup packet, setup data can be filled with underscore if 554190214Srpaulo * usbmon has not been able to read them, so we must parse this fields as 555190214Srpaulo * strings */ 556190214Srpaulo pcap_usb_setup* shdr; 557190214Srpaulo char str1[3], str2[3], str3[5], str4[5], str5[5]; 558190214Srpaulo ret = sscanf(string, "%s %s %s %s %s%n", str1, str2, str3, str4, 559190214Srpaulo str5, &cnt); 560190214Srpaulo if (ret < 5) 561190214Srpaulo { 562190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 563190214Srpaulo "Can't parse USB bus message '%s', too few tokens (expected 5 got %d)", 564190214Srpaulo string, ret); 565190214Srpaulo return -1; 566190214Srpaulo } 567190214Srpaulo string += cnt; 568190214Srpaulo 569190214Srpaulo /* try to convert to corresponding integer */ 570190214Srpaulo shdr = &uhdr->setup; 571190214Srpaulo shdr->bmRequestType = strtoul(str1, 0, 16); 572190214Srpaulo shdr->bRequest = strtoul(str2, 0, 16); 573190214Srpaulo shdr->wValue = htols(strtoul(str3, 0, 16)); 574190214Srpaulo shdr->wIndex = htols(strtoul(str4, 0, 16)); 575190214Srpaulo shdr->wLength = htols(strtoul(str5, 0, 16)); 576190214Srpaulo 577190214Srpaulo uhdr->setup_flag = 0; 578190214Srpaulo } 579190214Srpaulo else 580190214Srpaulo uhdr->setup_flag = 1; 581190214Srpaulo 582190214Srpaulo /* read urb data */ 583190214Srpaulo ret = sscanf(string, " %d%n", &urb_len, &cnt); 584190214Srpaulo if (ret < 1) 585190214Srpaulo { 586190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 587190214Srpaulo "Can't parse urb length from '%s'", string); 588190214Srpaulo return -1; 589190214Srpaulo } 590190214Srpaulo string += cnt; 591190214Srpaulo 592190214Srpaulo /* urb tag is not present if urb length is 0, so we can stop here 593190214Srpaulo * text parsing */ 594190214Srpaulo pkth.len = urb_len+pkth.caplen; 595190214Srpaulo uhdr->urb_len = urb_len; 596190214Srpaulo uhdr->data_flag = 1; 597190214Srpaulo data_len = 0; 598214518Srpaulo if (uhdr->urb_len == 0) 599190214Srpaulo goto got; 600190214Srpaulo 601190214Srpaulo /* check for data presence; data is present if and only if urb tag is '=' */ 602190214Srpaulo if (sscanf(string, " %c", &urb_tag) != 1) 603190214Srpaulo { 604190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 605190214Srpaulo "Can't parse urb tag from '%s'", string); 606190214Srpaulo return -1; 607190214Srpaulo } 608190214Srpaulo 609190214Srpaulo if (urb_tag != '=') 610190214Srpaulo goto got; 611190214Srpaulo 612190214Srpaulo /* skip urb tag and following space */ 613190214Srpaulo string += 3; 614190214Srpaulo 615190214Srpaulo /* if we reach this point we got some urb data*/ 616190214Srpaulo uhdr->data_flag = 0; 617190214Srpaulo 618190214Srpaulo /* read all urb data; if urb length is greater then the usbmon internal 619190214Srpaulo * buffer length used by the kernel to spool the URB, we get only 620190214Srpaulo * a partial information. 621190214Srpaulo * At least until linux 2.6.17 there is no way to set usbmon intenal buffer 622190214Srpaulo * length and default value is 130. */ 623190214Srpaulo while ((string[0] != 0) && (string[1] != 0) && (pkth.caplen < handle->snapshot)) 624190214Srpaulo { 625190214Srpaulo rawdata[0] = ascii_to_int(string[0]) * 16 + ascii_to_int(string[1]); 626190214Srpaulo rawdata++; 627190214Srpaulo string+=2; 628190214Srpaulo if (string[0] == ' ') 629190214Srpaulo string++; 630190214Srpaulo pkth.caplen++; 631190214Srpaulo data_len++; 632190214Srpaulo } 633190214Srpaulo 634190214Srpaulogot: 635190214Srpaulo uhdr->data_len = data_len; 636190214Srpaulo if (pkth.caplen > handle->snapshot) 637190214Srpaulo pkth.caplen = handle->snapshot; 638190214Srpaulo 639235426Sdelphij if (handle->fcode.bf_insns == NULL || 640235426Sdelphij bpf_filter(handle->fcode.bf_insns, handle->buffer, 641235426Sdelphij pkth.len, pkth.caplen)) { 642235426Sdelphij handle->md.packets_read++; 643235426Sdelphij callback(user, &pkth, handle->buffer); 644235426Sdelphij return 1; 645235426Sdelphij } 646235426Sdelphij return 0; /* didn't pass filter */ 647190214Srpaulo} 648190214Srpaulo 649190214Srpaulostatic int 650190214Srpaulousb_inject_linux(pcap_t *handle, const void *buf, size_t size) 651190214Srpaulo{ 652190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " 653190214Srpaulo "USB devices"); 654190214Srpaulo return (-1); 655190214Srpaulo} 656190214Srpaulo 657190214Srpaulostatic int 658190214Srpaulousb_stats_linux(pcap_t *handle, struct pcap_stat *stats) 659190214Srpaulo{ 660190214Srpaulo int dummy, ret, consumed, cnt; 661190214Srpaulo char string[USB_LINE_LEN]; 662190214Srpaulo char token[USB_LINE_LEN]; 663190214Srpaulo char * ptr = string; 664214518Srpaulo int fd; 665214518Srpaulo 666190214Srpaulo snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handle->md.ifindex); 667214518Srpaulo fd = open(string, O_RDONLY, 0); 668190214Srpaulo if (fd < 0) 669190214Srpaulo { 670214518Srpaulo if (errno == ENOENT) 671214518Srpaulo { 672214518Srpaulo /* 673214518Srpaulo * Not found at the new location; try the old 674214518Srpaulo * location. 675214518Srpaulo */ 676214518Srpaulo snprintf(string, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%ds", handle->md.ifindex); 677214518Srpaulo fd = open(string, O_RDONLY, 0); 678214518Srpaulo } 679214518Srpaulo if (fd < 0) { 680214518Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 681214518Srpaulo "Can't open USB stats file %s: %s", 682214518Srpaulo string, strerror(errno)); 683214518Srpaulo return -1; 684214518Srpaulo } 685190214Srpaulo } 686190214Srpaulo 687190214Srpaulo /* read stats line */ 688190214Srpaulo do { 689190214Srpaulo ret = read(fd, string, USB_LINE_LEN-1); 690190214Srpaulo } while ((ret == -1) && (errno == EINTR)); 691190214Srpaulo close(fd); 692190214Srpaulo 693190214Srpaulo if (ret < 0) 694190214Srpaulo { 695190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 696190214Srpaulo "Can't read stats from fd %d ", fd); 697190214Srpaulo return -1; 698190214Srpaulo } 699190214Srpaulo string[ret] = 0; 700190214Srpaulo 701190214Srpaulo /* extract info on dropped urbs */ 702190214Srpaulo for (consumed=0; consumed < ret; ) { 703190214Srpaulo /* from the sscanf man page: 704190214Srpaulo * The C standard says: "Execution of a %n directive does 705190214Srpaulo * not increment the assignment count returned at the completion 706190214Srpaulo * of execution" but the Corrigendum seems to contradict this. 707190214Srpaulo * Do not make any assumptions on the effect of %n conversions 708190214Srpaulo * on the return value and explicitly check for cnt assignmet*/ 709214518Srpaulo int ntok; 710214518Srpaulo 711190214Srpaulo cnt = -1; 712214518Srpaulo ntok = sscanf(ptr, "%s%n", token, &cnt); 713190214Srpaulo if ((ntok < 1) || (cnt < 0)) 714190214Srpaulo break; 715190214Srpaulo consumed += cnt; 716190214Srpaulo ptr += cnt; 717190214Srpaulo if (strcmp(token, "nreaders") == 0) 718190214Srpaulo ret = sscanf(ptr, "%d", &stats->ps_drop); 719190214Srpaulo else 720190214Srpaulo ret = sscanf(ptr, "%d", &dummy); 721190214Srpaulo if (ntok != 1) 722190214Srpaulo break; 723190214Srpaulo consumed += cnt; 724190214Srpaulo ptr += cnt; 725190214Srpaulo } 726190214Srpaulo 727190214Srpaulo stats->ps_recv = handle->md.packets_read; 728190214Srpaulo stats->ps_ifdrop = 0; 729190214Srpaulo return 0; 730190214Srpaulo} 731190214Srpaulo 732190214Srpaulostatic int 733190214Srpaulousb_setdirection_linux(pcap_t *p, pcap_direction_t d) 734190214Srpaulo{ 735190214Srpaulo p->direction = d; 736190214Srpaulo return 0; 737190214Srpaulo} 738190214Srpaulo 739190214Srpaulo 740190214Srpaulostatic int 741190214Srpaulousb_stats_linux_bin(pcap_t *handle, struct pcap_stat *stats) 742190214Srpaulo{ 743190214Srpaulo int ret; 744190214Srpaulo struct mon_bin_stats st; 745190214Srpaulo ret = ioctl(handle->fd, MON_IOCG_STATS, &st); 746190214Srpaulo if (ret < 0) 747190214Srpaulo { 748190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 749190214Srpaulo "Can't read stats from fd %d:%s ", handle->fd, strerror(errno)); 750190214Srpaulo return -1; 751190214Srpaulo } 752190214Srpaulo 753190214Srpaulo stats->ps_recv = handle->md.packets_read + st.queued; 754214518Srpaulo stats->ps_drop = st.dropped; 755214518Srpaulo stats->ps_ifdrop = 0; 756190214Srpaulo return 0; 757190214Srpaulo} 758190214Srpaulo 759190214Srpaulo/* 760190214Srpaulo * see <linux-kernel-source>/Documentation/usb/usbmon.txt and 761190214Srpaulo * <linux-kernel-source>/drivers/usb/mon/mon_bin.c binary ABI 762190214Srpaulo */ 763190214Srpaulostatic int 764190214Srpaulousb_read_linux_bin(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 765190214Srpaulo{ 766190214Srpaulo struct mon_bin_get info; 767190214Srpaulo int ret; 768190214Srpaulo struct pcap_pkthdr pkth; 769190214Srpaulo int clen = handle->snapshot - sizeof(pcap_usb_header); 770190214Srpaulo 771190214Srpaulo /* the usb header is going to be part of 'packet' data*/ 772190214Srpaulo info.hdr = (pcap_usb_header*) handle->buffer; 773190214Srpaulo info.data = handle->buffer + sizeof(pcap_usb_header); 774190214Srpaulo info.data_len = clen; 775190214Srpaulo 776190214Srpaulo /* ignore interrupt system call errors */ 777190214Srpaulo do { 778190214Srpaulo ret = ioctl(handle->fd, MON_IOCX_GET, &info); 779190214Srpaulo if (handle->break_loop) 780190214Srpaulo { 781190214Srpaulo handle->break_loop = 0; 782190214Srpaulo return -2; 783190214Srpaulo } 784190214Srpaulo } while ((ret == -1) && (errno == EINTR)); 785190214Srpaulo if (ret < 0) 786190214Srpaulo { 787190214Srpaulo if (errno == EAGAIN) 788190214Srpaulo return 0; /* no data there */ 789190214Srpaulo 790190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 791190214Srpaulo "Can't read from fd %d: %s", handle->fd, strerror(errno)); 792190214Srpaulo return -1; 793190214Srpaulo } 794190214Srpaulo 795190214Srpaulo /* we can get less that than really captured from kernel, depending on 796190214Srpaulo * snaplen, so adjust header accordingly */ 797190214Srpaulo if (info.hdr->data_len < clen) 798190214Srpaulo clen = info.hdr->data_len; 799190214Srpaulo info.hdr->data_len = clen; 800190214Srpaulo pkth.caplen = clen + sizeof(pcap_usb_header); 801214518Srpaulo pkth.len = info.hdr->data_len + sizeof(pcap_usb_header); 802190214Srpaulo pkth.ts.tv_sec = info.hdr->ts_sec; 803190214Srpaulo pkth.ts.tv_usec = info.hdr->ts_usec; 804190214Srpaulo 805235426Sdelphij if (handle->fcode.bf_insns == NULL || 806235426Sdelphij bpf_filter(handle->fcode.bf_insns, handle->buffer, 807235426Sdelphij pkth.len, pkth.caplen)) { 808235426Sdelphij handle->md.packets_read++; 809235426Sdelphij callback(user, &pkth, handle->buffer); 810235426Sdelphij return 1; 811235426Sdelphij } 812235426Sdelphij 813235426Sdelphij return 0; /* didn't pass filter */ 814190214Srpaulo} 815190214Srpaulo 816190214Srpaulo/* 817190214Srpaulo * see <linux-kernel-source>/Documentation/usb/usbmon.txt and 818190214Srpaulo * <linux-kernel-source>/drivers/usb/mon/mon_bin.c binary ABI 819190214Srpaulo */ 820190214Srpaulo#define VEC_SIZE 32 821190214Srpaulostatic int 822190214Srpaulousb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 823190214Srpaulo{ 824190214Srpaulo struct mon_bin_mfetch fetch; 825190214Srpaulo int32_t vec[VEC_SIZE]; 826190214Srpaulo struct pcap_pkthdr pkth; 827190214Srpaulo pcap_usb_header* hdr; 828190214Srpaulo int nflush = 0; 829190214Srpaulo int packets = 0; 830214518Srpaulo int clen, max_clen; 831190214Srpaulo 832214518Srpaulo max_clen = handle->snapshot - sizeof(pcap_usb_header); 833214518Srpaulo 834190214Srpaulo for (;;) { 835190214Srpaulo int i, ret; 836190214Srpaulo int limit = max_packets - packets; 837190214Srpaulo if (limit <= 0) 838190214Srpaulo limit = VEC_SIZE; 839190214Srpaulo if (limit > VEC_SIZE) 840190214Srpaulo limit = VEC_SIZE; 841190214Srpaulo 842190214Srpaulo /* try to fetch as many events as possible*/ 843190214Srpaulo fetch.offvec = vec; 844190214Srpaulo fetch.nfetch = limit; 845190214Srpaulo fetch.nflush = nflush; 846190214Srpaulo /* ignore interrupt system call errors */ 847190214Srpaulo do { 848190214Srpaulo ret = ioctl(handle->fd, MON_IOCX_MFETCH, &fetch); 849190214Srpaulo if (handle->break_loop) 850190214Srpaulo { 851190214Srpaulo handle->break_loop = 0; 852190214Srpaulo return -2; 853190214Srpaulo } 854190214Srpaulo } while ((ret == -1) && (errno == EINTR)); 855190214Srpaulo if (ret < 0) 856190214Srpaulo { 857190214Srpaulo if (errno == EAGAIN) 858190214Srpaulo return 0; /* no data there */ 859190214Srpaulo 860190214Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 861190214Srpaulo "Can't mfetch fd %d: %s", handle->fd, strerror(errno)); 862190214Srpaulo return -1; 863190214Srpaulo } 864190214Srpaulo 865190214Srpaulo /* keep track of processed events, we will flush them later */ 866190214Srpaulo nflush = fetch.nfetch; 867190214Srpaulo for (i=0; i<fetch.nfetch; ++i) { 868190214Srpaulo /* discard filler */ 869214518Srpaulo hdr = (pcap_usb_header*) &handle->md.mmapbuf[vec[i]]; 870190214Srpaulo if (hdr->event_type == '@') 871190214Srpaulo continue; 872190214Srpaulo 873214518Srpaulo /* we can get less that than really captured from kernel, depending on 874214518Srpaulo * snaplen, so adjust header accordingly */ 875214518Srpaulo clen = max_clen; 876214518Srpaulo if (hdr->data_len < clen) 877214518Srpaulo clen = hdr->data_len; 878214518Srpaulo 879190214Srpaulo /* get packet info from header*/ 880214518Srpaulo pkth.caplen = clen + sizeof(pcap_usb_header_mmapped); 881214518Srpaulo pkth.len = hdr->data_len + sizeof(pcap_usb_header_mmapped); 882190214Srpaulo pkth.ts.tv_sec = hdr->ts_sec; 883190214Srpaulo pkth.ts.tv_usec = hdr->ts_usec; 884190214Srpaulo 885235426Sdelphij if (handle->fcode.bf_insns == NULL || 886235426Sdelphij bpf_filter(handle->fcode.bf_insns, (u_char*) hdr, 887235426Sdelphij pkth.len, pkth.caplen)) { 888235426Sdelphij handle->md.packets_read++; 889235426Sdelphij callback(user, &pkth, (u_char*) hdr); 890235426Sdelphij packets++; 891235426Sdelphij } 892190214Srpaulo } 893190214Srpaulo 894190214Srpaulo /* with max_packets <= 0 we stop afer the first chunk*/ 895190214Srpaulo if ((max_packets <= 0) || (packets == max_packets)) 896190214Srpaulo break; 897190214Srpaulo } 898190214Srpaulo 899190214Srpaulo /* flush pending events*/ 900190214Srpaulo ioctl(handle->fd, MON_IOCH_MFLUSH, nflush); 901190214Srpaulo return packets; 902190214Srpaulo} 903190214Srpaulo 904190214Srpaulostatic void 905190214Srpaulousb_cleanup_linux_mmap(pcap_t* handle) 906190214Srpaulo{ 907214518Srpaulo /* if we have a memory-mapped buffer, unmap it */ 908214518Srpaulo if (handle->md.mmapbuf != NULL) { 909214518Srpaulo munmap(handle->md.mmapbuf, handle->md.mmapbuflen); 910214518Srpaulo handle->md.mmapbuf = NULL; 911214518Srpaulo } 912190214Srpaulo pcap_cleanup_live_common(handle); 913190214Srpaulo} 914