diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | lib/Makefile | 16 | ||||
-rw-r--r-- | read-dev-usbmon.c | 167 |
4 files changed, 139 insertions, 52 deletions
@@ -2,3 +2,5 @@ read-dev-usbmon hidraw ltunify +*.o +*.a @@ -9,6 +9,9 @@ udevrulesdir ?= /etc/udev/rules.d udevrule = 42-logitech-unify-permissions.rules +# Whether to support reading pcap files in read-dev-usbmon +WITH_PCAP ?= 1 + PACKAGE_VERSION ?= $(shell git describe --dirty 2>/dev/null | sed s/^v//) ifeq (PACKAGE_VERSION, "") LTUNIFY_DEFINES := @@ -22,6 +25,9 @@ endif all: ltunify read-dev-usbmon read-dev-usbmon: read-dev-usbmon.c hidraw.c +ifeq ($(WITH_PCAP), 1) + $(CC) $(CFLAGS) -o $(OUTDIR)$@ $< -lpcap -DWITH_PCAP=1 +endif ltunify: ltunify.c hidpp20.c $(CC) $(CFLAGS) -o $(OUTDIR)$@ $< -lrt $(LTUNIFY_DEFINES) diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..8d1bdaf --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,16 @@ + +CFLAGS ?= -O2 -g -DENABLE_TRACING +WFLAGS ?= -Wall -Wextra -Wmissing-prototypes + +SOURCES := $(wildcard *.c) +OBJECTS := $(SOURCES:%.c=%.o) + +libltunify.a: $(OBJECTS) + #$(CC) $(WFLAGS) $(CFLAGS) -o $@ $^ -lrt -c + ar rcs $@ $^ + +clean: + $(RM) libltunify.a $(OBJECTS) + +%.o: %.c + $(CC) -c $(WFLAGS) $(CFLAGS) -o $@ $< diff --git a/read-dev-usbmon.c b/read-dev-usbmon.c index bd1c1a6..ba6c296 100644 --- a/read-dev-usbmon.c +++ b/read-dev-usbmon.c @@ -3,7 +3,7 @@ * Because of limitations of a single output stream, there is currently a hack * that directly includes hidraw.c. * - * Copyright (C) 2013 Peter Wu <lekensteyn@gmail.com> + * Copyright (C) 2013-2014 Peter Wu <peter@lekensteyn.nl> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,11 @@ */ #include <fcntl.h> +#ifdef WITH_PCAP +# include <pcap/pcap.h> +# include <sys/types.h> +# include <sys/stat.h> +#endif #include <unistd.h> #include <stdio.h> #include <sys/ioctl.h> @@ -80,34 +85,64 @@ struct mon_get_arg { #include "hidraw.c" #undef NO_MAIN -void print_time(void) { - struct timeval tval; +void print_time(const struct timeval *tval) { struct tm *tm; - if (gettimeofday(&tval, NULL)) { - perror("gettimeofday"); - return; - } - tm = localtime(&tval.tv_sec); + tm = localtime(&tval->tv_sec); printf("%02d:%02d:%02d.%03ld ", tm->tm_hour, tm->tm_min, tm->tm_sec, - tval.tv_usec / 1000); + tval->tv_usec / 1000); +} + +void process_usbpkt(const struct usbmon_packet *hdr, const unsigned char *data, + const struct timeval *tval); + +#ifdef WITH_PCAP +static void packet_callback(u_char *user, const struct pcap_pkthdr *h, + const u_char *bytes) { + const struct usbmon_packet *hdr; + const unsigned char *data; + (void) user; + + if (h->caplen < sizeof(struct usbmon_packet)) { + return; + } + + hdr = (struct usbmon_packet *) bytes; + data = bytes + sizeof(*hdr); + process_usbpkt(hdr, data, &h->ts); } -int main(int argc, char ** argv) { +int main_pcap(char *filename) { + pcap_t *p; + char errbuf[PCAP_ERRBUF_SIZE]; + int r; + + p = pcap_open_offline(filename, errbuf); + if (p == NULL) { + fprintf(stderr, "%s\n", errbuf); + return 1; + } + + r = pcap_loop(p, -1, packet_callback, NULL); + if (r == -1) { + pcap_perror(p, filename); + } + pcap_close(p); + return 0; +} +#endif + +int main_usbmon(char *filename) { unsigned char data[1024]; struct usbmon_packet hdr; struct mon_get_arg event; int fd, r; + struct timeval tval = { 0, 0 }; - if (argc < 2) { - fprintf(stderr, "Usage: %s /dev/usbmonX\n", argv[0]); - return 1; - } - - fd = open(argv[1], O_RDONLY); + fd = open(filename, O_RDONLY); if (fd < 0) { - perror(argv[1]); + perror(filename); return 1; } @@ -129,45 +164,73 @@ int main(int argc, char ** argv) { break; } - // ignore non-data packets - if (hdr.len_cap) { - if (getenv("HEX")) { - unsigned int i; - printf("Type=%c\n", hdr.type); - for (i=0; i<hdr.len_cap; i++) { - printf("%02X%c", data[i], - i + 1 == hdr.len_cap ? '\n' : ' '); - } - } else if (hdr.len_cap > sizeof (struct report)) { - fprintf(stderr, "Discarding too large packet of length %u!\n", hdr.len_cap); - } else { - struct report *report = (struct report *)&data; - if (hdr.len_cap < 3) { - fprintf(stderr, "Short data len: %i\n", hdr.len_cap); - continue; - } -#define COLOR(c, cstr) "\033[" c "m" cstr "\033[m" - print_time(); - if (hdr.type == 'C') { - printf(COLOR("1;32", "Recv\t")); - } else if (hdr.type == 'S') { - printf(COLOR("1;31", "Send\t")); - } else { - printf(COLOR("1;35", "Type=%c\t") "\n", hdr.type); - } - process_msg(report, hdr.len_cap); - fflush(NULL); -#if 0 - if (write(STDOUT_FILENO, &data, hdr.len_cap) < 0) { - perror("write"); - break; - } -#endif - } + if (gettimeofday(&tval, NULL)) { + perror("gettimeofday"); } + process_usbpkt(&hdr, data, &tval); } close(fd); return 0; } + +int main(int argc, char **argv) { + char *filename; + if (argc < 2) { + fprintf(stderr, "Usage: %s </dev/usbmonX | - | foo.pcap>\n", + argv[0]); + return 1; + } + filename = argv[1]; +#ifdef WITH_PCAP + struct stat sbuf; + /* assume that usbmon files are devices, and pcap are files. + * "-" does not exist, so assume pcap if file cannot be stat()ed. */ + if (stat(filename, &sbuf) != 0 || !S_ISCHR(sbuf.st_mode)) { + return main_pcap(filename); + } +#endif + return main_usbmon(filename); +} + +void process_usbpkt(const struct usbmon_packet *hdr, const unsigned char *data, + const struct timeval *tval) { + // ignore non-data packets + if (!hdr->len_cap) { + return; + } + if (getenv("HEX")) { + unsigned int i; + printf("Type=%c\n", hdr->type); + for (i=0; i<hdr->len_cap; i++) { + printf("%02X%c", data[i], + i + 1 == hdr->len_cap ? '\n' : ' '); + } + } else if (hdr->len_cap > sizeof (struct report)) { + fprintf(stderr, "Discarding too large packet of length %u!\n", hdr->len_cap); + } else { + struct report *report = (struct report *)data; + if (hdr->len_cap < 3) { + fprintf(stderr, "Short data len: %i\n", hdr->len_cap); + return; + } +#define COLOR(c, cstr) "\033[" c "m" cstr "\033[m" + print_time(tval); + if (hdr->type == 'C') { + printf(COLOR("1;32", "Recv\t")); + } else if (hdr->type == 'S') { + printf(COLOR("1;31", "Send\t")); + } else { + printf(COLOR("1;35", "Type=%c\t") "\n", hdr->type); + } + process_msg(report, hdr->len_cap); + fflush(NULL); +#if 0 + if (write(STDOUT_FILENO, data, hdr->len_cap) < 0) { + perror("write"); + break; + } +#endif + } +} |