]> The Tcpdump Group git mirrors - libpcap/blob - pcap-usb-linux.c
Give N. Leiten credit for the poll() exceptional condition checks in
[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 close(handle->fd);
388 return PCAP_ERROR;
389 }
390 return 0;
391 }
392
393 static inline int
394 ascii_to_int(char c)
395 {
396 return c < 'A' ? c- '0': ((c<'a') ? c - 'A' + 10: c-'a'+10);
397 }
398
399 /*
400 * see <linux-kernel-source>/Documentation/usb/usbmon.txt and
401 * <linux-kernel-source>/drivers/usb/mon/mon_text.c for urb string
402 * format description
403 */
404 static int
405 usb_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
406 {
407 /* see:
408 * /usr/src/linux/Documentation/usb/usbmon.txt
409 * for message format
410 */
411 unsigned timestamp;
412 int tag, cnt, ep_num, dev_addr, dummy, ret, urb_len, data_len;
413 char etype, pipeid1, pipeid2, status[16], urb_tag, line[USB_LINE_LEN];
414 char *string = line;
415 u_char * rawdata = handle->buffer;
416 struct pcap_pkthdr pkth;
417 pcap_usb_header* uhdr = (pcap_usb_header*)handle->buffer;
418 u_char urb_transfer=0;
419 int incoming=0;
420
421 /* ignore interrupt system call errors */
422 do {
423 ret = read(handle->fd, line, USB_LINE_LEN - 1);
424 if (handle->break_loop)
425 {
426 handle->break_loop = 0;
427 return -2;
428 }
429 } while ((ret == -1) && (errno == EINTR));
430 if (ret < 0)
431 {
432 if (errno == EAGAIN)
433 return 0; /* no data there */
434
435 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
436 "Can't read from fd %d: %s", handle->fd, strerror(errno));
437 return -1;
438 }
439
440 /* read urb header; %n argument may increment return value, but it's
441 * not mandatory, so does not count on it*/
442 string[ret] = 0;
443 ret = sscanf(string, "%x %d %c %c%c:%d:%d %s%n", &tag, &timestamp, &etype,
444 &pipeid1, &pipeid2, &dev_addr, &ep_num, status,
445 &cnt);
446 if (ret < 8)
447 {
448 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
449 "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)",
450 string, ret);
451 return -1;
452 }
453 uhdr->id = tag;
454 uhdr->device_address = dev_addr;
455 uhdr->bus_id = handle->md.ifindex;
456 uhdr->status = 0;
457 string += cnt;
458
459 /* don't use usbmon provided timestamp, since it have low precision*/
460 if (gettimeofday(&pkth.ts, NULL) < 0)
461 {
462 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
463 "Can't get timestamp for message '%s' %d:%s",
464 string, errno, strerror(errno));
465 return -1;
466 }
467 uhdr->ts_sec = pkth.ts.tv_sec;
468 uhdr->ts_usec = pkth.ts.tv_usec;
469
470 /* parse endpoint information */
471 if (pipeid1 == 'C')
472 urb_transfer = URB_CONTROL;
473 else if (pipeid1 == 'Z')
474 urb_transfer = URB_ISOCHRONOUS;
475 else if (pipeid1 == 'I')
476 urb_transfer = URB_INTERRUPT;
477 else if (pipeid1 == 'B')
478 urb_transfer = URB_BULK;
479 if (pipeid2 == 'i') {
480 ep_num |= URB_TRANSFER_IN;
481 incoming = 1;
482 }
483 if (etype == 'C')
484 incoming = !incoming;
485
486 /* direction check*/
487 if (incoming)
488 {
489 if (handle->direction == PCAP_D_OUT)
490 return 0;
491 }
492 else
493 if (handle->direction == PCAP_D_IN)
494 return 0;
495 uhdr->event_type = etype;
496 uhdr->transfer_type = urb_transfer;
497 uhdr->endpoint_number = ep_num;
498 pkth.caplen = sizeof(pcap_usb_header);
499 rawdata += sizeof(pcap_usb_header);
500
501 /* check if this is a setup packet */
502 ret = sscanf(status, "%d", &dummy);
503 if (ret != 1)
504 {
505 /* this a setup packet, setup data can be filled with underscore if
506 * usbmon has not been able to read them, so we must parse this fields as
507 * strings */
508 pcap_usb_setup* shdr;
509 char str1[3], str2[3], str3[5], str4[5], str5[5];
510 ret = sscanf(string, "%s %s %s %s %s%n", str1, str2, str3, str4,
511 str5, &cnt);
512 if (ret < 5)
513 {
514 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
515 "Can't parse USB bus message '%s', too few tokens (expected 5 got %d)",
516 string, ret);
517 return -1;
518 }
519 string += cnt;
520
521 /* try to convert to corresponding integer */
522 shdr = &uhdr->setup;
523 shdr->bmRequestType = strtoul(str1, 0, 16);
524 shdr->bRequest = strtoul(str2, 0, 16);
525 shdr->wValue = htols(strtoul(str3, 0, 16));
526 shdr->wIndex = htols(strtoul(str4, 0, 16));
527 shdr->wLength = htols(strtoul(str5, 0, 16));
528
529 uhdr->setup_flag = 0;
530 }
531 else
532 uhdr->setup_flag = 1;
533
534 /* read urb data */
535 ret = sscanf(string, " %d%n", &urb_len, &cnt);
536 if (ret < 1)
537 {
538 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
539 "Can't parse urb length from '%s'", string);
540 return -1;
541 }
542 string += cnt;
543
544 /* urb tag is not present if urb length is 0, so we can stop here
545 * text parsing */
546 pkth.len = urb_len+pkth.caplen;
547 uhdr->urb_len = urb_len;
548 uhdr->data_flag = 1;
549 data_len = 0;
550 if (uhdr->urb_len == 0)
551 goto got;
552
553 /* check for data presence; data is present if and only if urb tag is '=' */
554 if (sscanf(string, " %c", &urb_tag) != 1)
555 {
556 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
557 "Can't parse urb tag from '%s'", string);
558 return -1;
559 }
560
561 if (urb_tag != '=')
562 goto got;
563
564 /* skip urb tag and following space */
565 string += 3;
566
567 /* if we reach this point we got some urb data*/
568 uhdr->data_flag = 0;
569
570 /* read all urb data; if urb length is greater then the usbmon internal
571 * buffer length used by the kernel to spool the URB, we get only
572 * a partial information.
573 * At least until linux 2.6.17 there is no way to set usbmon intenal buffer
574 * length and default value is 130. */
575 while ((string[0] != 0) && (string[1] != 0) && (pkth.caplen < handle->snapshot))
576 {
577 rawdata[0] = ascii_to_int(string[0]) * 16 + ascii_to_int(string[1]);
578 rawdata++;
579 string+=2;
580 if (string[0] == ' ')
581 string++;
582 pkth.caplen++;
583 data_len++;
584 }
585
586 got:
587 uhdr->data_len = data_len;
588 handle->md.packets_read++;
589 if (pkth.caplen > handle->snapshot)
590 pkth.caplen = handle->snapshot;
591
592 callback(user, &pkth, handle->buffer);
593 return 1;
594 }
595
596 static int
597 usb_inject_linux(pcap_t *handle, const void *buf, size_t size)
598 {
599 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on "
600 "USB devices");
601 return (-1);
602 }
603
604 static int
605 usb_stats_linux(pcap_t *handle, struct pcap_stat *stats)
606 {
607 int dummy, ret, consumed, cnt;
608 char string[USB_LINE_LEN];
609 char token[USB_LINE_LEN];
610 char * ptr = string;
611 int fd;
612
613 snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handle->md.ifindex);
614 fd = open(string, O_RDONLY, 0);
615 if (fd < 0)
616 {
617 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
618 "Can't open USB stats file %s: %s",
619 string, strerror(errno));
620 return -1;
621 }
622
623 /* read stats line */
624 do {
625 ret = read(fd, string, USB_LINE_LEN-1);
626 } while ((ret == -1) && (errno == EINTR));
627 close(fd);
628
629 if (ret < 0)
630 {
631 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
632 "Can't read stats from fd %d ", fd);
633 return -1;
634 }
635 string[ret] = 0;
636
637 /* extract info on dropped urbs */
638 for (consumed=0; consumed < ret; ) {
639 /* from the sscanf man page:
640 * The C standard says: "Execution of a %n directive does
641 * not increment the assignment count returned at the completion
642 * of execution" but the Corrigendum seems to contradict this.
643 * Do not make any assumptions on the effect of %n conversions
644 * on the return value and explicitly check for cnt assignmet*/
645 int ntok;
646
647 cnt = -1;
648 ntok = sscanf(ptr, "%s%n", token, &cnt);
649 if ((ntok < 1) || (cnt < 0))
650 break;
651 consumed += cnt;
652 ptr += cnt;
653 if (strcmp(token, "nreaders") == 0)
654 ret = sscanf(ptr, "%d", &stats->ps_drop);
655 else
656 ret = sscanf(ptr, "%d", &dummy);
657 if (ntok != 1)
658 break;
659 consumed += cnt;
660 ptr += cnt;
661 }
662
663 stats->ps_recv = handle->md.packets_read;
664 stats->ps_ifdrop = 0;
665 return 0;
666 }
667
668 static int
669 usb_setfilter_linux(pcap_t *p, struct bpf_program *fp)
670 {
671 return 0;
672 }
673
674 static int
675 usb_setdirection_linux(pcap_t *p, pcap_direction_t d)
676 {
677 p->direction = d;
678 return 0;
679 }
680
681
682 static int
683 usb_stats_linux_bin(pcap_t *handle, struct pcap_stat *stats)
684 {
685 int ret;
686 struct mon_bin_stats st;
687 ret = ioctl(handle->fd, MON_IOCG_STATS, &st);
688 if (ret < 0)
689 {
690 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
691 "Can't read stats from fd %d:%s ", handle->fd, strerror(errno));
692 return -1;
693 }
694
695 stats->ps_recv = handle->md.packets_read + st.queued;
696 stats->ps_drop = st.dropped;
697 stats->ps_ifdrop = 0;
698 return 0;
699 }
700
701 /*
702 * see <linux-kernel-source>/Documentation/usb/usbmon.txt and
703 * <linux-kernel-source>/drivers/usb/mon/mon_bin.c binary ABI
704 */
705 static int
706 usb_read_linux_bin(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
707 {
708 struct mon_bin_get info;
709 int ret;
710 struct pcap_pkthdr pkth;
711 int clen = handle->snapshot - sizeof(pcap_usb_header);
712
713 /* the usb header is going to be part of 'packet' data*/
714 info.hdr = (pcap_usb_header*) handle->buffer;
715 info.data = handle->buffer + sizeof(pcap_usb_header);
716 info.data_len = clen;
717
718 /* ignore interrupt system call errors */
719 do {
720 ret = ioctl(handle->fd, MON_IOCX_GET, &info);
721 if (handle->break_loop)
722 {
723 handle->break_loop = 0;
724 return -2;
725 }
726 } while ((ret == -1) && (errno == EINTR));
727 if (ret < 0)
728 {
729 if (errno == EAGAIN)
730 return 0; /* no data there */
731
732 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
733 "Can't read from fd %d: %s", handle->fd, strerror(errno));
734 return -1;
735 }
736
737 /* we can get less that than really captured from kernel, depending on
738 * snaplen, so adjust header accordingly */
739 if (info.hdr->data_len < clen)
740 clen = info.hdr->data_len;
741 info.hdr->data_len = clen;
742 pkth.caplen = clen + sizeof(pcap_usb_header);
743 pkth.len = info.hdr->data_len + sizeof(pcap_usb_header);
744 pkth.ts.tv_sec = info.hdr->ts_sec;
745 pkth.ts.tv_usec = info.hdr->ts_usec;
746
747 handle->md.packets_read++;
748 callback(user, &pkth, handle->buffer);
749 return 1;
750 }
751
752 /*
753 * see <linux-kernel-source>/Documentation/usb/usbmon.txt and
754 * <linux-kernel-source>/drivers/usb/mon/mon_bin.c binary ABI
755 */
756 #define VEC_SIZE 32
757 static int
758 usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
759 {
760 struct mon_bin_mfetch fetch;
761 int32_t vec[VEC_SIZE];
762 struct pcap_pkthdr pkth;
763 pcap_usb_header* hdr;
764 int nflush = 0;
765 int packets = 0;
766 int clen, max_clen;
767
768 max_clen = handle->snapshot - sizeof(pcap_usb_header);
769
770 for (;;) {
771 int i, ret;
772 int limit = max_packets - packets;
773 if (limit <= 0)
774 limit = VEC_SIZE;
775 if (limit > VEC_SIZE)
776 limit = VEC_SIZE;
777
778 /* try to fetch as many events as possible*/
779 fetch.offvec = vec;
780 fetch.nfetch = limit;
781 fetch.nflush = nflush;
782 /* ignore interrupt system call errors */
783 do {
784 ret = ioctl(handle->fd, MON_IOCX_MFETCH, &fetch);
785 if (handle->break_loop)
786 {
787 handle->break_loop = 0;
788 return -2;
789 }
790 } while ((ret == -1) && (errno == EINTR));
791 if (ret < 0)
792 {
793 if (errno == EAGAIN)
794 return 0; /* no data there */
795
796 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
797 "Can't mfetch fd %d: %s", handle->fd, strerror(errno));
798 return -1;
799 }
800
801 /* keep track of processed events, we will flush them later */
802 nflush = fetch.nfetch;
803 for (i=0; i<fetch.nfetch; ++i) {
804 /* discard filler */
805 hdr = (pcap_usb_header*) &handle->md.mmapbuf[vec[i]];
806 if (hdr->event_type == '@')
807 continue;
808
809 /* we can get less that than really captured from kernel, depending on
810 * snaplen, so adjust header accordingly */
811 clen = max_clen;
812 if (hdr->data_len < clen)
813 clen = hdr->data_len;
814
815 /* get packet info from header*/
816 pkth.caplen = clen + sizeof(pcap_usb_header_mmapped);
817 pkth.len = hdr->data_len + sizeof(pcap_usb_header_mmapped);
818 pkth.ts.tv_sec = hdr->ts_sec;
819 pkth.ts.tv_usec = hdr->ts_usec;
820
821 handle->md.packets_read++;
822 callback(user, &pkth, (u_char*) hdr);
823 packets++;
824 }
825
826 /* with max_packets <= 0 we stop afer the first chunk*/
827 if ((max_packets <= 0) || (packets == max_packets))
828 break;
829 }
830
831 /* flush pending events*/
832 ioctl(handle->fd, MON_IOCH_MFLUSH, nflush);
833 return packets;
834 }
835
836 static void
837 usb_cleanup_linux_mmap(pcap_t* handle)
838 {
839 /* if we have a memory-mapped buffer, unmap it */
840 if (handle->md.mmapbuf != NULL) {
841 munmap(handle->md.mmapbuf, handle->md.mmapbuflen);
842 handle->md.mmapbuf = NULL;
843 }
844 pcap_cleanup_live_common(handle);
845 }