]> The Tcpdump Group git mirrors - libpcap/blob - pcap-usb-linux.c
From Dustin Spicuzza:
[libpcap] / pcap-usb-linux.c
1 /*
2 * Copyright (c) 2006 Paolo Abeni (Italy)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 * products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * USB sniffing API implementation for Linux platform
31 * By Paolo Abeni <paolo.abeni@email.it>
32 * Modifications: Kris Katterjohn <katterjohn@gmail.com>
33 *
34 */
35 #ifndef lint
36 static const char rcsid[] _U_ =
37 "@(#) $Header: /tcpdump/master/libpcap/pcap-usb-linux.c,v 1.33 2008-12-23 21:38:50 guy Exp $ (LBL)";
38 #endif
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #include "pcap-int.h"
45 #include "pcap-usb-linux.h"
46 #include "pcap/usb.h"
47
48 #ifdef NEED_STRERROR_H
49 #include "strerror.h"
50 #endif
51
52 #include <ctype.h>
53 #include <errno.h>
54 #include <stdlib.h>
55 #include <unistd.h>
56 #include <fcntl.h>
57 #include <string.h>
58 #include <dirent.h>
59 #include <byteswap.h>
60 #include <netinet/in.h>
61 #include <sys/ioctl.h>
62 #include <sys/mman.h>
63 #ifdef HAVE_LINUX_USBDEVICE_FS_H
64 #include <linux/usbdevice_fs.h>
65 #endif
66
67 #define USB_IFACE "usbmon"
68 #define USB_TEXT_DIR "/sys/kernel/debug/usbmon"
69 #define SYS_USB_BUS_DIR "/sys/bus/usb/devices"
70 #define PROC_USB_BUS_DIR "/proc/bus/usb"
71 #define USB_LINE_LEN 4096
72
73 #if __BYTE_ORDER == __LITTLE_ENDIAN
74 #define htols(s) s
75 #define htoll(l) l
76 #define htol64(ll) ll
77 #else
78 #define htols(s) bswap_16(s)
79 #define htoll(l) bswap_32(l)
80 #define htol64(ll) bswap_64(ll)
81 #endif
82
83 struct mon_bin_stats {
84 u_int32_t queued;
85 u_int32_t dropped;
86 };
87
88 struct mon_bin_get {
89 pcap_usb_header *hdr;
90 void *data;
91 size_t data_len; /* Length of data (can be zero) */
92 };
93
94 struct mon_bin_mfetch {
95 int32_t *offvec; /* Vector of events fetched */
96 int32_t nfetch; /* Number of events to fetch (out: fetched) */
97 int32_t nflush; /* Number of events to flush */
98 };
99
100 #define MON_IOC_MAGIC 0x92
101
102 #define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
103 #define MON_IOCX_URB _IOWR(MON_IOC_MAGIC, 2, struct mon_bin_hdr)
104 #define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
105 #define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
106 #define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
107 #define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
108 #define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
109 #define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
110
111 #define MON_BIN_SETUP 0x1 /* setup hdr is present*/
112 #define MON_BIN_SETUP_ZERO 0x2 /* setup buffer is not available */
113 #define MON_BIN_DATA_ZERO 0x4 /* data buffer is not available */
114 #define MON_BIN_ERROR 0x8
115
116 /* forward declaration */
117 static int usb_activate(pcap_t *);
118 static int usb_stats_linux(pcap_t *, struct pcap_stat *);
119 static int usb_stats_linux_bin(pcap_t *, struct pcap_stat *);
120 static int usb_read_linux(pcap_t *, int , pcap_handler , u_char *);
121 static int usb_read_linux_bin(pcap_t *, int , pcap_handler , u_char *);
122 static int usb_read_linux_mmap(pcap_t *, int , pcap_handler , u_char *);
123 static int usb_inject_linux(pcap_t *, const void *, size_t);
124 static int usb_setfilter_linux(pcap_t *, struct bpf_program *);
125 static int usb_setdirection_linux(pcap_t *, pcap_direction_t);
126 static void usb_cleanup_linux_mmap(pcap_t *);
127
128 /* facility to add an USB device to the device list*/
129 static int
130 usb_dev_add(pcap_if_t** alldevsp, int n, char *err_str)
131 {
132 char dev_name[10];
133 char dev_descr[30];
134 snprintf(dev_name, 10, USB_IFACE"%d", n);
135 snprintf(dev_descr, 30, "USB bus number %d", n);
136
137 if (pcap_add_if(alldevsp, dev_name, 0,
138 dev_descr, err_str) < 0)
139 return -1;
140 return 0;
141 }
142
143 int
144 usb_platform_finddevs(pcap_if_t **alldevsp, char *err_str)
145 {
146 struct dirent* data;
147 int ret = 0;
148 DIR* dir;
149 int n;
150 char* name;
151 size_t len;
152
153 /* try scanning sysfs usb bus directory */
154 dir = opendir(SYS_USB_BUS_DIR);
155 if (dir != NULL) {
156 while ((ret == 0) && ((data = readdir(dir)) != 0)) {
157 name = data->d_name;
158
159 if (strncmp(name, "usb", 3) != 0)
160 continue;
161
162 if (sscanf(&name[3], "%d", &n) == 0)
163 continue;
164
165 ret = usb_dev_add(alldevsp, n, err_str);
166 }
167
168 closedir(dir);
169 return ret;
170 }
171
172 /* that didn't work; try scanning procfs usb bus directory */
173 dir = opendir(PROC_USB_BUS_DIR);
174 if (dir != NULL) {
175 while ((ret == 0) && ((data = readdir(dir)) != 0)) {
176 name = data->d_name;
177 len = strlen(name);
178
179 /* if this file name does not end with a number it's not of our interest */
180 if ((len < 1) || !isdigit(name[--len]))
181 continue;
182 while (isdigit(name[--len]));
183 if (sscanf(&name[len+1], "%d", &n) != 1)
184 continue;
185
186 ret = usb_dev_add(alldevsp, n, err_str);
187 }
188
189 closedir(dir);
190 return ret;
191 }
192
193 /* neither of them worked */
194 return 0;
195 }
196
197 static
198 int usb_mmap(pcap_t* handle)
199 {
200 int len = ioctl(handle->fd, MON_IOCQ_RING_SIZE);
201 if (len < 0)
202 return 0;
203
204 handle->md.mmapbuflen = len;
205 handle->md.mmapbuf = mmap(0, handle->md.mmapbuflen, PROT_READ,
206 MAP_SHARED, handle->fd, 0);
207 return handle->md.mmapbuf != MAP_FAILED;
208 }
209
210 #define CTRL_TIMEOUT (5*1000) /* milliseconds */
211
212 #define USB_DIR_IN 0x80
213 #define USB_TYPE_STANDARD 0x00
214 #define USB_RECIP_DEVICE 0x00
215
216 #define USB_REQ_GET_DESCRIPTOR 6
217
218 #define USB_DT_DEVICE 1
219
220 /* probe the descriptors of the devices attached to the bus */
221 /* the descriptors will end up in the captured packet stream */
222 /* and be decoded by external apps like wireshark */
223 /* without these identifying probes packet data can't be fully decoded */
224 static void
225 probe_devices(int bus)
226 {
227 struct usbdevfs_ctrltransfer ctrl;
228 struct dirent* data;
229 int ret = 0;
230 char buf[40];
231 DIR* dir;
232
233 /* scan usb bus directories for device nodes */
234 snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d", bus);
235 dir = opendir(buf);
236 if (!dir)
237 return;
238
239 while ((ret >= 0) && ((data = readdir(dir)) != 0)) {
240 int fd;
241 char* name = data->d_name;
242
243 if (name[0] == '.')
244 continue;
245
246 snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d/%s", bus, data->d_name);
247
248 fd = open(buf, O_RDWR);
249 if (fd == -1)
250 continue;
251
252 /*
253 * Sigh. Different kernels have different member names
254 * for this structure.
255 */
256 #ifdef HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE
257 ctrl.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
258 ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
259 ctrl.wValue = USB_DT_DEVICE << 8;
260 ctrl.wIndex = 0;
261 ctrl.wLength = sizeof(buf);
262 #else
263 ctrl.requesttype = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
264 ctrl.request = USB_REQ_GET_DESCRIPTOR;
265 ctrl.value = USB_DT_DEVICE << 8;
266 ctrl.index = 0;
267 ctrl.length = sizeof(buf);
268 #endif
269 ctrl.data = buf;
270 ctrl.timeout = CTRL_TIMEOUT;
271
272 ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
273
274 close(fd);
275 }
276 closedir(dir);
277 }
278
279 pcap_t *
280 usb_create(const char *device, char *ebuf)
281 {
282 pcap_t *p;
283
284 p = pcap_create_common(device, ebuf);
285 if (p == NULL)
286 return (NULL);
287
288 p->activate_op = usb_activate;
289 return (p);
290 }
291
292 static int
293 usb_activate(pcap_t* handle)
294 {
295 char full_path[USB_LINE_LEN];
296
297 /* Initialize some components of the pcap structure. */
298 handle->bufsize = handle->snapshot;
299 handle->offset = 0;
300 handle->linktype = DLT_USB_LINUX;
301
302 handle->inject_op = usb_inject_linux;
303 handle->setfilter_op = usb_setfilter_linux;
304 handle->setdirection_op = usb_setdirection_linux;
305 handle->set_datalink_op = NULL; /* can't change data link type */
306 handle->getnonblock_op = pcap_getnonblock_fd;
307 handle->setnonblock_op = pcap_setnonblock_fd;
308
309 /*get usb bus index from device name */
310 if (sscanf(handle->opt.source, USB_IFACE"%d", &handle->md.ifindex) != 1)
311 {
312 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
313 "Can't get USB bus index from %s", handle->opt.source);
314 return PCAP_ERROR;
315 }
316
317 /*now select the read method: try to open binary interface */
318 snprintf(full_path, USB_LINE_LEN, LINUX_USB_MON_DEV"%d", handle->md.ifindex);
319 handle->fd = open(full_path, O_RDONLY, 0);
320 if (handle->fd >= 0)
321 {
322 if (handle->opt.rfmon) {
323 /*
324 * Monitor mode doesn't apply to USB devices.
325 */
326 close(handle->fd);
327 return PCAP_ERROR_RFMON_NOTSUP;
328 }
329
330 /* binary api is available, try to use fast mmap access */
331 if (usb_mmap(handle)) {
332 handle->linktype = DLT_USB_LINUX_MMAPPED;
333 handle->stats_op = usb_stats_linux_bin;
334 handle->read_op = usb_read_linux_mmap;
335 handle->cleanup_op = usb_cleanup_linux_mmap;
336 probe_devices(handle->md.ifindex);
337
338 /*
339 * "handle->fd" is a real file, so "select()" and
340 * "poll()" work on it.
341 */
342 handle->selectable_fd = handle->fd;
343 return 0;
344 }
345
346 /* can't mmap, use plain binary interface access */
347 handle->stats_op = usb_stats_linux_bin;
348 handle->read_op = usb_read_linux_bin;
349 probe_devices(handle->md.ifindex);
350 }
351 else {
352 /*Binary interface not available, try open text interface */
353 snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR"/%dt", handle->md.ifindex);
354 handle->fd = open(full_path, O_RDONLY, 0);
355 if (handle->fd < 0)
356 {
357 /* no more fallback, give it up*/
358 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
359 "Can't open USB bus file %s: %s", full_path, strerror(errno));
360 return PCAP_ERROR;
361 }
362
363 if (handle->opt.rfmon) {
364 /*
365 * Monitor mode doesn't apply to USB devices.
366 */
367 close(handle->fd);
368 return PCAP_ERROR_RFMON_NOTSUP;
369 }
370
371 handle->stats_op = usb_stats_linux;
372 handle->read_op = usb_read_linux;
373 }
374
375 /*
376 * "handle->fd" is a real file, so "select()" and "poll()"
377 * work on it.
378 */
379 handle->selectable_fd = handle->fd;
380
381 /* for plain binary access and text access we need to allocate the read
382 * buffer */
383 handle->buffer = malloc(handle->bufsize);
384 if (!handle->buffer) {
385 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
386 "malloc: %s", pcap_strerror(errno));
387 return PCAP_ERROR;
388 }
389 return 0;
390 }
391
392 static inline int
393 ascii_to_int(char c)
394 {
395 return c < 'A' ? c- '0': ((c<'a') ? c - 'A' + 10: c-'a'+10);
396 }
397
398 /*
399 * see <linux-kernel-source>/Documentation/usb/usbmon.txt and
400 * <linux-kernel-source>/drivers/usb/mon/mon_text.c for urb string
401 * format description
402 */
403 static int
404 usb_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
405 {
406 /* see:
407 * /usr/src/linux/Documentation/usb/usbmon.txt
408 * for message format
409 */
410 unsigned timestamp;
411 int tag, cnt, ep_num, dev_addr, dummy, ret, urb_len, data_len;
412 char etype, pipeid1, pipeid2, status[16], urb_tag, line[USB_LINE_LEN];
413 char *string = line;
414 u_char * rawdata = handle->buffer;
415 struct pcap_pkthdr pkth;
416 pcap_usb_header* uhdr = (pcap_usb_header*)handle->buffer;
417 u_char urb_transfer=0;
418 int incoming=0;
419
420 /* ignore interrupt system call errors */
421 do {
422 ret = read(handle->fd, line, USB_LINE_LEN - 1);
423 if (handle->break_loop)
424 {
425 handle->break_loop = 0;
426 return -2;
427 }
428 } while ((ret == -1) && (errno == EINTR));
429 if (ret < 0)
430 {
431 if (errno == EAGAIN)
432 return 0; /* no data there */
433
434 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
435 "Can't read from fd %d: %s", handle->fd, strerror(errno));
436 return -1;
437 }
438
439 /* read urb header; %n argument may increment return value, but it's
440 * not mandatory, so does not count on it*/
441 string[ret] = 0;
442 ret = sscanf(string, "%x %d %c %c%c:%d:%d %s%n", &tag, &timestamp, &etype,
443 &pipeid1, &pipeid2, &dev_addr, &ep_num, status,
444 &cnt);
445 if (ret < 8)
446 {
447 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
448 "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)",
449 string, ret);
450 return -1;
451 }
452 uhdr->id = tag;
453 uhdr->device_address = dev_addr;
454 uhdr->bus_id = handle->md.ifindex;
455 uhdr->status = 0;
456 string += cnt;
457
458 /* don't use usbmon provided timestamp, since it have low precision*/
459 if (gettimeofday(&pkth.ts, NULL) < 0)
460 {
461 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
462 "Can't get timestamp for message '%s' %d:%s",
463 string, errno, strerror(errno));
464 return -1;
465 }
466 uhdr->ts_sec = pkth.ts.tv_sec;
467 uhdr->ts_usec = pkth.ts.tv_usec;
468
469 /* parse endpoint information */
470 if (pipeid1 == 'C')
471 urb_transfer = URB_CONTROL;
472 else if (pipeid1 == 'Z')
473 urb_transfer = URB_ISOCHRONOUS;
474 else if (pipeid1 == 'I')
475 urb_transfer = URB_INTERRUPT;
476 else if (pipeid1 == 'B')
477 urb_transfer = URB_BULK;
478 if (pipeid2 == 'i') {
479 ep_num |= URB_TRANSFER_IN;
480 incoming = 1;
481 }
482 if (etype == 'C')
483 incoming = !incoming;
484
485 /* direction check*/
486 if (incoming)
487 {
488 if (handle->direction == PCAP_D_OUT)
489 return 0;
490 }
491 else
492 if (handle->direction == PCAP_D_IN)
493 return 0;
494 uhdr->event_type = etype;
495 uhdr->transfer_type = urb_transfer;
496 uhdr->endpoint_number = ep_num;
497 pkth.caplen = sizeof(pcap_usb_header);
498 rawdata += sizeof(pcap_usb_header);
499
500 /* check if this is a setup packet */
501 ret = sscanf(status, "%d", &dummy);
502 if (ret != 1)
503 {
504 /* this a setup packet, setup data can be filled with underscore if
505 * usbmon has not been able to read them, so we must parse this fields as
506 * strings */
507 pcap_usb_setup* shdr;
508 char str1[3], str2[3], str3[5], str4[5], str5[5];
509 ret = sscanf(string, "%s %s %s %s %s%n", str1, str2, str3, str4,
510 str5, &cnt);
511 if (ret < 5)
512 {
513 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
514 "Can't parse USB bus message '%s', too few tokens (expected 5 got %d)",
515 string, ret);
516 return -1;
517 }
518 string += cnt;
519
520 /* try to convert to corresponding integer */
521 shdr = &uhdr->setup;
522 shdr->bmRequestType = strtoul(str1, 0, 16);
523 shdr->bRequest = strtoul(str2, 0, 16);
524 shdr->wValue = htols(strtoul(str3, 0, 16));
525 shdr->wIndex = htols(strtoul(str4, 0, 16));
526 shdr->wLength = htols(strtoul(str5, 0, 16));
527
528 uhdr->setup_flag = 0;
529 }
530 else
531 uhdr->setup_flag = 1;
532
533 /* read urb data */
534 ret = sscanf(string, " %d%n", &urb_len, &cnt);
535 if (ret < 1)
536 {
537 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
538 "Can't parse urb length from '%s'", string);
539 return -1;
540 }
541 string += cnt;
542
543 /* urb tag is not present if urb length is 0, so we can stop here
544 * text parsing */
545 pkth.len = urb_len+pkth.caplen;
546 uhdr->urb_len = urb_len;
547 uhdr->data_flag = 1;
548 data_len = 0;
549 if (uhdr->urb_len == 0)
550 goto got;
551
552 /* check for data presence; data is present if and only if urb tag is '=' */
553 if (sscanf(string, " %c", &urb_tag) != 1)
554 {
555 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
556 "Can't parse urb tag from '%s'", string);
557 return -1;
558 }
559
560 if (urb_tag != '=')
561 goto got;
562
563 /* skip urb tag and following space */
564 string += 3;
565
566 /* if we reach this point we got some urb data*/
567 uhdr->data_flag = 0;
568
569 /* read all urb data; if urb length is greater then the usbmon internal
570 * buffer length used by the kernel to spool the URB, we get only
571 * a partial information.
572 * At least until linux 2.6.17 there is no way to set usbmon intenal buffer
573 * length and default value is 130. */
574 while ((string[0] != 0) && (string[1] != 0) && (pkth.caplen < handle->snapshot))
575 {
576 rawdata[0] = ascii_to_int(string[0]) * 16 + ascii_to_int(string[1]);
577 rawdata++;
578 string+=2;
579 if (string[0] == ' ')
580 string++;
581 pkth.caplen++;
582 data_len++;
583 }
584
585 got:
586 uhdr->data_len = data_len;
587 handle->md.packets_read++;
588 if (pkth.caplen > handle->snapshot)
589 pkth.caplen = handle->snapshot;
590
591 callback(user, &pkth, handle->buffer);
592 return 1;
593 }
594
595 static int
596 usb_inject_linux(pcap_t *handle, const void *buf, size_t size)
597 {
598 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on "
599 "USB devices");
600 return (-1);
601 }
602
603 static int
604 usb_stats_linux(pcap_t *handle, struct pcap_stat *stats)
605 {
606 int dummy, ret, consumed, cnt;
607 char string[USB_LINE_LEN];
608 char token[USB_LINE_LEN];
609 char * ptr = string;
610 int fd;
611
612 snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handle->md.ifindex);
613 fd = open(string, O_RDONLY, 0);
614 if (fd < 0)
615 {
616 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
617 "Can't open USB stats file %s: %s",
618 string, strerror(errno));
619 return -1;
620 }
621
622 /* read stats line */
623 do {
624 ret = read(fd, string, USB_LINE_LEN-1);
625 } while ((ret == -1) && (errno == EINTR));
626 close(fd);
627
628 if (ret < 0)
629 {
630 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
631 "Can't read stats from fd %d ", fd);
632 return -1;
633 }
634 string[ret] = 0;
635
636 /* extract info on dropped urbs */
637 for (consumed=0; consumed < ret; ) {
638 /* from the sscanf man page:
639 * The C standard says: "Execution of a %n directive does
640 * not increment the assignment count returned at the completion
641 * of execution" but the Corrigendum seems to contradict this.
642 * Do not make any assumptions on the effect of %n conversions
643 * on the return value and explicitly check for cnt assignmet*/
644 int ntok;
645
646 cnt = -1;
647 ntok = sscanf(ptr, "%s%n", token, &cnt);
648 if ((ntok < 1) || (cnt < 0))
649 break;
650 consumed += cnt;
651 ptr += cnt;
652 if (strcmp(token, "nreaders") == 0)
653 ret = sscanf(ptr, "%d", &stats->ps_drop);
654 else
655 ret = sscanf(ptr, "%d", &dummy);
656 if (ntok != 1)
657 break;
658 consumed += cnt;
659 ptr += cnt;
660 }
661
662 stats->ps_recv = handle->md.packets_read;
663 stats->ps_ifdrop = 0;
664 return 0;
665 }
666
667 static int
668 usb_setfilter_linux(pcap_t *p, struct bpf_program *fp)
669 {
670 return 0;
671 }
672
673 static int
674 usb_setdirection_linux(pcap_t *p, pcap_direction_t d)
675 {
676 p->direction = d;
677 return 0;
678 }
679
680
681 static int
682 usb_stats_linux_bin(pcap_t *handle, struct pcap_stat *stats)
683 {
684 int ret;
685 struct mon_bin_stats st;
686 ret = ioctl(handle->fd, MON_IOCG_STATS, &st);
687 if (ret < 0)
688 {
689 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
690 "Can't read stats from fd %d:%s ", handle->fd, strerror(errno));
691 return -1;
692 }
693
694 stats->ps_recv = handle->md.packets_read + st.queued;
695 stats->ps_ifdrop = 0;
696 stats->ps_drop = st.dropped;
697 return 0;
698 }
699
700 /*
701 * see <linux-kernel-source>/Documentation/usb/usbmon.txt and
702 * <linux-kernel-source>/drivers/usb/mon/mon_bin.c binary ABI
703 */
704 static int
705 usb_read_linux_bin(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
706 {
707 struct mon_bin_get info;
708 int ret;
709 struct pcap_pkthdr pkth;
710 int clen = handle->snapshot - sizeof(pcap_usb_header);
711
712 /* the usb header is going to be part of 'packet' data*/
713 info.hdr = (pcap_usb_header*) handle->buffer;
714 info.data = handle->buffer + sizeof(pcap_usb_header);
715 info.data_len = clen;
716
717 /* ignore interrupt system call errors */
718 do {
719 ret = ioctl(handle->fd, MON_IOCX_GET, &info);
720 if (handle->break_loop)
721 {
722 handle->break_loop = 0;
723 return -2;
724 }
725 } while ((ret == -1) && (errno == EINTR));
726 if (ret < 0)
727 {
728 if (errno == EAGAIN)
729 return 0; /* no data there */
730
731 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
732 "Can't read from fd %d: %s", handle->fd, strerror(errno));
733 return -1;
734 }
735
736 /* we can get less that than really captured from kernel, depending on
737 * snaplen, so adjust header accordingly */
738 if (info.hdr->data_len < clen)
739 clen = info.hdr->data_len;
740 info.hdr->data_len = clen;
741 pkth.caplen = clen + sizeof(pcap_usb_header);
742 pkth.len = info.hdr->data_len + sizeof(pcap_usb_header);
743 pkth.ts.tv_sec = info.hdr->ts_sec;
744 pkth.ts.tv_usec = info.hdr->ts_usec;
745
746 handle->md.packets_read++;
747 callback(user, &pkth, handle->buffer);
748 return 1;
749 }
750
751 /*
752 * see <linux-kernel-source>/Documentation/usb/usbmon.txt and
753 * <linux-kernel-source>/drivers/usb/mon/mon_bin.c binary ABI
754 */
755 #define VEC_SIZE 32
756 static int
757 usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
758 {
759 struct mon_bin_mfetch fetch;
760 int32_t vec[VEC_SIZE];
761 struct pcap_pkthdr pkth;
762 pcap_usb_header* hdr;
763 int nflush = 0;
764 int packets = 0;
765 int clen, max_clen;
766
767 max_clen = handle->snapshot - sizeof(pcap_usb_header);
768
769 for (;;) {
770 int i, ret;
771 int limit = max_packets - packets;
772 if (limit <= 0)
773 limit = VEC_SIZE;
774 if (limit > VEC_SIZE)
775 limit = VEC_SIZE;
776
777 /* try to fetch as many events as possible*/
778 fetch.offvec = vec;
779 fetch.nfetch = limit;
780 fetch.nflush = nflush;
781 /* ignore interrupt system call errors */
782 do {
783 ret = ioctl(handle->fd, MON_IOCX_MFETCH, &fetch);
784 if (handle->break_loop)
785 {
786 handle->break_loop = 0;
787 return -2;
788 }
789 } while ((ret == -1) && (errno == EINTR));
790 if (ret < 0)
791 {
792 if (errno == EAGAIN)
793 return 0; /* no data there */
794
795 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
796 "Can't mfetch fd %d: %s", handle->fd, strerror(errno));
797 return -1;
798 }
799
800 /* keep track of processed events, we will flush them later */
801 nflush = fetch.nfetch;
802 for (i=0; i<fetch.nfetch; ++i) {
803 /* discard filler */
804 hdr = (pcap_usb_header*) &handle->md.mmapbuf[vec[i]];
805 if (hdr->event_type == '@')
806 continue;
807
808 /* we can get less that than really captured from kernel, depending on
809 * snaplen, so adjust header accordingly */
810 clen = max_clen;
811 if (hdr->data_len < clen)
812 clen = hdr->data_len;
813
814 /* get packet info from header*/
815 pkth.caplen = clen + sizeof(pcap_usb_header_mmapped);
816 pkth.len = hdr->data_len + sizeof(pcap_usb_header_mmapped);
817 pkth.ts.tv_sec = hdr->ts_sec;
818 pkth.ts.tv_usec = hdr->ts_usec;
819
820 handle->md.packets_read++;
821 callback(user, &pkth, (u_char*) hdr);
822 packets++;
823 }
824
825 /* with max_packets <= 0 we stop afer the first chunk*/
826 if ((max_packets <= 0) || (packets == max_packets))
827 break;
828 }
829
830 /* flush pending events*/
831 ioctl(handle->fd, MON_IOCH_MFLUSH, nflush);
832 return packets;
833 }
834
835 static void
836 usb_cleanup_linux_mmap(pcap_t* handle)
837 {
838 /* if we have a memory-mapped buffer, unmap it */
839 if (handle->md.mmapbuf != NULL) {
840 munmap(handle->md.mmapbuf, handle->md.mmapbuflen);
841 handle->md.mmapbuf = NULL;
842 }
843 pcap_cleanup_live_common(handle);
844 }